@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
package/dist/cli/plan.cjs CHANGED
@@ -30,17 +30,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // src/engine/plan-engine.ts
34
- function keywordMatch(eventText, step) {
35
- const stepText = [
36
- step.label,
37
- step.description ?? "",
38
- ...step.tags ?? []
33
+ // src/engine/text-utils.ts
34
+ function normalizeEventText(event) {
35
+ return [
36
+ event.intent,
37
+ event.tool ?? "",
38
+ event.scope ?? ""
39
39
  ].join(" ").toLowerCase();
40
- const keywords = stepText.split(/\s+/).filter((w) => w.length > 3);
40
+ }
41
+ function extractKeywords(text, minLength = 3) {
42
+ return text.toLowerCase().split(/\s+/).filter((w) => w.length > minLength);
43
+ }
44
+ function matchesAllKeywords(eventText, ruleText) {
45
+ const keywords = extractKeywords(ruleText);
46
+ if (keywords.length === 0) return false;
47
+ return keywords.every((kw) => eventText.includes(kw));
48
+ }
49
+ function matchesKeywordThreshold(eventText, ruleText, threshold = 0.5) {
50
+ const keywords = extractKeywords(ruleText);
41
51
  if (keywords.length === 0) return false;
42
52
  const matched = keywords.filter((kw) => eventText.includes(kw));
43
- return matched.length >= Math.ceil(keywords.length * 0.5);
53
+ return matched.length >= Math.ceil(keywords.length * threshold);
44
54
  }
45
55
  function tokenSimilarity(a, b) {
46
56
  const tokensA = new Set(a.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
@@ -53,6 +63,24 @@ function tokenSimilarity(a, b) {
53
63
  const union = (/* @__PURE__ */ new Set([...tokensA, ...tokensB])).size;
54
64
  return union > 0 ? intersection / union : 0;
55
65
  }
66
+ var init_text_utils = __esm({
67
+ "src/engine/text-utils.ts"() {
68
+ "use strict";
69
+ }
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
+ }
56
84
  function findMatchingStep(eventText, event, steps) {
57
85
  const pendingOrActive = steps.filter((s) => s.status === "pending" || s.status === "active");
58
86
  if (pendingOrActive.length === 0) {
@@ -71,7 +99,7 @@ function findMatchingStep(eventText, event, steps) {
71
99
  let bestScore = 0;
72
100
  for (const step of pendingOrActive) {
73
101
  const stepText = [step.label, step.description ?? "", ...step.tags ?? []].join(" ");
74
- const score = tokenSimilarity(intentText, stepText);
102
+ const score = tokenSimilarity2(intentText, stepText);
75
103
  if (score > bestScore) {
76
104
  bestScore = score;
77
105
  bestStep = step;
@@ -112,7 +140,7 @@ function checkConstraints(event, eventText, constraints) {
112
140
  continue;
113
141
  }
114
142
  if (constraint.type === "scope" && constraint.trigger) {
115
- const keywords = constraint.trigger.split(/\s+/).filter((w) => w.length > 3);
143
+ const keywords = extractKeywords(constraint.trigger);
116
144
  const violated = keywords.length > 0 && keywords.every((kw) => eventText.includes(kw));
117
145
  checks.push({
118
146
  constraintId: constraint.id,
@@ -193,11 +221,7 @@ function evaluatePlan(event, plan) {
193
221
  progress
194
222
  };
195
223
  }
196
- const eventText = [
197
- event.intent,
198
- event.tool ?? "",
199
- event.scope ?? ""
200
- ].join(" ").toLowerCase();
224
+ const eventText = normalizeEventText(event);
201
225
  const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
202
226
  if (!matched) {
203
227
  return {
@@ -238,7 +262,7 @@ function evaluatePlan(event, plan) {
238
262
  };
239
263
  }
240
264
  function buildPlanCheck(event, plan, verdict) {
241
- const eventText = [event.intent, event.tool ?? "", event.scope ?? ""].join(" ").toLowerCase();
265
+ const eventText = normalizeEventText(event);
242
266
  const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
243
267
  const { checks: constraintChecks } = checkConstraints(event, eventText, plan.constraints);
244
268
  const progress = getPlanProgress(plan);
@@ -258,12 +282,672 @@ function buildPlanCheck(event, plan, verdict) {
258
282
  var init_plan_engine = __esm({
259
283
  "src/engine/plan-engine.ts"() {
260
284
  "use strict";
285
+ init_text_utils();
286
+ }
287
+ });
288
+
289
+ // src/engine/bootstrap-parser.ts
290
+ var bootstrap_parser_exports = {};
291
+ __export(bootstrap_parser_exports, {
292
+ parseWorldMarkdown: () => parseWorldMarkdown
293
+ });
294
+ function splitSections(markdown) {
295
+ const lines = markdown.split("\n");
296
+ let frontmatter = "";
297
+ let bodyStart = 0;
298
+ if (lines[0]?.trim() === "---") {
299
+ const endIdx = lines.indexOf("---", 1);
300
+ if (endIdx > 0) {
301
+ frontmatter = lines.slice(1, endIdx).join("\n");
302
+ bodyStart = endIdx + 1;
303
+ }
304
+ }
305
+ const sections = [];
306
+ let currentSection = null;
307
+ const contentLines = [];
308
+ for (let i = bodyStart; i < lines.length; i++) {
309
+ const line = lines[i];
310
+ if (line.startsWith("# ")) {
311
+ if (currentSection) {
312
+ currentSection.content = contentLines.join("\n").trim();
313
+ sections.push(currentSection);
314
+ contentLines.length = 0;
315
+ }
316
+ currentSection = {
317
+ name: line.replace(/^#\s+/, "").trim(),
318
+ content: "",
319
+ startLine: i + 1
320
+ // 1-based
321
+ };
322
+ } else if (currentSection) {
323
+ contentLines.push(line);
324
+ }
325
+ }
326
+ if (currentSection) {
327
+ currentSection.content = contentLines.join("\n").trim();
328
+ sections.push(currentSection);
329
+ }
330
+ return { frontmatter, sections };
331
+ }
332
+ function parseFrontmatter2(yaml, issues) {
333
+ const result = {};
334
+ for (const line of yaml.split("\n")) {
335
+ const trimmed = line.trim();
336
+ if (!trimmed || trimmed.startsWith("#")) continue;
337
+ const colonIdx = trimmed.indexOf(":");
338
+ if (colonIdx === -1) continue;
339
+ const key = trimmed.slice(0, colonIdx).trim();
340
+ const value = trimmed.slice(colonIdx + 1).trim();
341
+ result[key] = value;
342
+ }
343
+ if (!result.world_id) {
344
+ issues.push({ line: 1, section: "frontmatter", message: "Missing world_id in frontmatter", severity: "error" });
345
+ }
346
+ if (!result.name) {
347
+ issues.push({ line: 1, section: "frontmatter", message: "Missing name in frontmatter", severity: "error" });
348
+ }
349
+ return {
350
+ world_id: result.world_id ?? "",
351
+ name: result.name ?? "",
352
+ version: result.version,
353
+ runtime_mode: result.runtime_mode,
354
+ default_profile: result.default_profile,
355
+ alternative_profile: result.alternative_profile
356
+ };
357
+ }
358
+ function parseThesis(content, startLine, issues) {
359
+ const thesis = content.trim();
360
+ if (!thesis) {
361
+ issues.push({ line: startLine, section: "Thesis", message: "Thesis section is empty", severity: "error" });
362
+ }
363
+ return thesis;
364
+ }
365
+ function parseInvariants(content, startLine, issues) {
366
+ const invariants = [];
367
+ const lines = content.split("\n");
368
+ for (let i = 0; i < lines.length; i++) {
369
+ const line = lines[i].trim();
370
+ if (!line.startsWith("- ")) continue;
371
+ const lineNum = startLine + i + 1;
372
+ const match = line.match(
373
+ /^-\s+`([^`]+)`\s*[—–-]\s*(.+?)(?:\s*\(([^)]+)\))?\s*$/
374
+ );
375
+ if (match) {
376
+ const id = match[1];
377
+ const label = match[2].trim();
378
+ const parens = match[3] ?? "structural, immutable";
379
+ const enforcement = parens.includes("prompt") ? "prompt" : parens.includes("operational") ? "operational" : "structural";
380
+ const mutable = parens.includes("mutable") && !parens.includes("immutable");
381
+ invariants.push({ id, label, enforcement, mutable, line: lineNum });
382
+ } else {
383
+ const fallback = line.match(/^-\s+\*\*([^*]+)\*\*\s*[—–-]\s*(.+)/);
384
+ if (fallback) {
385
+ const id = fallback[1].toLowerCase().replace(/\s+/g, "_");
386
+ const label = fallback[2].trim();
387
+ invariants.push({ id, label, enforcement: "structural", mutable: false, line: lineNum });
388
+ } else {
389
+ issues.push({ line: lineNum, section: "Invariants", message: `Could not parse invariant: "${line}"`, severity: "warning" });
390
+ }
391
+ }
392
+ }
393
+ if (invariants.length === 0) {
394
+ issues.push({ line: startLine, section: "Invariants", message: "No invariants found", severity: "error" });
395
+ }
396
+ return invariants;
397
+ }
398
+ function parseStateVariables(content, startLine, issues) {
399
+ const variables = [];
400
+ const subSections = splitH2Sections(content, startLine);
401
+ for (const sub of subSections) {
402
+ const props = parseKeyValueBullets(sub.content);
403
+ const lineNum = sub.startLine;
404
+ const type = props.type;
405
+ if (!type) {
406
+ issues.push({ line: lineNum, section: "State", message: `Variable "${sub.name}" missing type`, severity: "error" });
407
+ continue;
408
+ }
409
+ let defaultVal = props.default ?? "";
410
+ if (type === "number") {
411
+ defaultVal = parseFloat(String(defaultVal)) || 0;
412
+ } else if (type === "boolean") {
413
+ defaultVal = String(defaultVal).toLowerCase() === "true";
414
+ }
415
+ const variable = {
416
+ id: sub.name,
417
+ type,
418
+ default: defaultVal,
419
+ label: props.label ?? sub.name,
420
+ description: props.description ?? "",
421
+ line: lineNum
422
+ };
423
+ if (type === "number") {
424
+ if (props.min !== void 0) variable.min = parseFloat(props.min);
425
+ if (props.max !== void 0) variable.max = parseFloat(props.max);
426
+ if (props.step !== void 0) variable.step = parseFloat(props.step);
427
+ }
428
+ if (type === "enum" && props.options) {
429
+ variable.options = props.options.split(",").map((s) => s.trim());
430
+ }
431
+ variables.push(variable);
432
+ }
433
+ return variables;
434
+ }
435
+ function parseAssumptions(content, startLine, issues) {
436
+ const profiles = [];
437
+ const subSections = splitH2Sections(content, startLine);
438
+ for (const sub of subSections) {
439
+ const props = parseKeyValueBullets(sub.content);
440
+ const name = props.name ?? sub.name;
441
+ const description = props.description ?? "";
442
+ const parameters = {};
443
+ for (const [key, val] of Object.entries(props)) {
444
+ if (key === "name" || key === "description") continue;
445
+ if (val === "true") parameters[key] = true;
446
+ else if (val === "false") parameters[key] = false;
447
+ else if (!isNaN(Number(val)) && val.trim() !== "") parameters[key] = Number(val);
448
+ else parameters[key] = val;
449
+ }
450
+ profiles.push({
451
+ id: sub.name,
452
+ name,
453
+ description,
454
+ parameters,
455
+ line: sub.startLine
456
+ });
457
+ }
458
+ return profiles;
459
+ }
460
+ function parseRules(content, startLine, issues) {
461
+ const rules = [];
462
+ const subSections = splitH2Sections(content, startLine);
463
+ for (let ruleIdx = 0; ruleIdx < subSections.length; ruleIdx++) {
464
+ const sub = subSections[ruleIdx];
465
+ const lineNum = sub.startLine;
466
+ const headingMatch = sub.name.match(/^([^:]+):\s*(.+?)(?:\s*\(([^)]+)\))?\s*$/);
467
+ const id = headingMatch ? headingMatch[1].trim() : `rule-${String(ruleIdx + 1).padStart(3, "0")}`;
468
+ const label = headingMatch ? headingMatch[2].trim() : sub.name;
469
+ const severity = headingMatch?.[3]?.trim() ?? "degradation";
470
+ const lines = sub.content.split("\n");
471
+ let description = "";
472
+ const triggers = [];
473
+ const effects = [];
474
+ let collapseCheck;
475
+ const causalParts = {};
476
+ for (let i = 0; i < lines.length; i++) {
477
+ const line = lines[i].trim();
478
+ if (line.startsWith("When ")) {
479
+ const triggerStr = line.slice(5);
480
+ const parts = triggerStr.split(/\s+AND\s+/i);
481
+ for (const part of parts) {
482
+ const trigger = parseTriggerExpression(part.trim());
483
+ if (trigger) triggers.push(trigger);
484
+ else issues.push({ line: lineNum + i, section: "Rules", message: `Could not parse trigger: "${part}"`, severity: "warning" });
485
+ }
486
+ } else if (line.startsWith("Then ")) {
487
+ const effectStr = line.slice(5);
488
+ const parts = effectStr.split(",");
489
+ for (const part of parts) {
490
+ const effect = parseEffectExpression(part.trim());
491
+ if (effect) effects.push(effect);
492
+ else issues.push({ line: lineNum + i, section: "Rules", message: `Could not parse effect: "${part}"`, severity: "warning" });
493
+ }
494
+ } else if (line.startsWith("Collapse:")) {
495
+ const collapseStr = line.slice(9).trim();
496
+ const collapse = parseCollapseExpression(collapseStr);
497
+ if (collapse) collapseCheck = collapse;
498
+ else issues.push({ line: lineNum + i, section: "Rules", message: `Could not parse collapse: "${collapseStr}"`, severity: "warning" });
499
+ } else if (line.startsWith("> ")) {
500
+ const causalMatch = line.match(/^>\s*(trigger|rule|shift|effect):\s*(.+)/i);
501
+ if (causalMatch) {
502
+ causalParts[causalMatch[1].toLowerCase()] = causalMatch[2].trim();
503
+ }
504
+ } else if (line && !line.startsWith("-") && !line.startsWith("#")) {
505
+ if (!description) description = line;
506
+ else description += " " + line;
507
+ }
508
+ }
509
+ if (triggers.length === 0) {
510
+ issues.push({ line: lineNum, section: "Rules", message: `Rule "${id}" has no triggers (missing "When" line)`, severity: "warning" });
511
+ }
512
+ if (effects.length === 0) {
513
+ issues.push({ line: lineNum, section: "Rules", message: `Rule "${id}" has no effects (missing "Then" line)`, severity: "warning" });
514
+ }
515
+ const causal_translation = Object.keys(causalParts).length > 0 ? {
516
+ trigger_text: causalParts.trigger ?? "",
517
+ rule_text: causalParts.rule ?? "",
518
+ shift_text: causalParts.shift ?? "",
519
+ effect_text: causalParts.effect ?? ""
520
+ } : void 0;
521
+ rules.push({
522
+ id,
523
+ label,
524
+ severity,
525
+ description: description || void 0,
526
+ order: ruleIdx + 1,
527
+ triggers,
528
+ effects,
529
+ collapse_check: collapseCheck,
530
+ causal_translation,
531
+ line: lineNum
532
+ });
533
+ }
534
+ return rules;
535
+ }
536
+ function parseTriggerExpression(expr) {
537
+ const match = expr.match(
538
+ /^(\w+)\s*(==|!=|>=|<=|>|<|in)\s*(.+?)\s*\[(state|assumption)\]\s*$/
539
+ );
540
+ if (!match) return null;
541
+ const field = match[1];
542
+ const operator = match[2];
543
+ let value = match[3].trim();
544
+ const source = match[4];
545
+ value = parseValueLiteral(value);
546
+ return { field, operator, value, source };
547
+ }
548
+ function parseEffectExpression(expr) {
549
+ const compound = expr.match(/^(\w+)\s*(\*=|\+=|-=)\s*(.+)$/);
550
+ if (compound) {
551
+ const target = compound[1];
552
+ const op = compound[2];
553
+ const value = parseValueLiteral(compound[3].trim());
554
+ const operationMap = {
555
+ "*=": "multiply",
556
+ "+=": "add",
557
+ "-=": "subtract"
558
+ };
559
+ return { target, operation: operationMap[op], value };
560
+ }
561
+ const assignment = expr.match(/^(\w+)\s*=\s*(.+)$/);
562
+ if (assignment) {
563
+ const target = assignment[1];
564
+ const value = parseValueLiteral(assignment[2].trim());
565
+ const operation = typeof value === "boolean" ? "set_boolean" : "set";
566
+ return { target, operation, value };
567
+ }
568
+ return null;
569
+ }
570
+ function parseCollapseExpression(expr) {
571
+ const cleaned = expr.replace(/\s*→.*$/, "").trim();
572
+ const match = cleaned.match(/^(\w+)\s*(==|!=|>=|<=|>|<)\s*([\d.]+)$/);
573
+ if (!match) return null;
574
+ return {
575
+ field: match[1],
576
+ operator: match[2],
577
+ value: parseFloat(match[3])
578
+ };
579
+ }
580
+ function parseGates(content, startLine, issues) {
581
+ const gates = [];
582
+ const lines = content.split("\n");
583
+ for (let i = 0; i < lines.length; i++) {
584
+ const line = lines[i].trim();
585
+ if (!line.startsWith("- ")) continue;
586
+ const lineNum = startLine + i + 1;
587
+ const match = line.match(/^-\s+(\w+):\s*(\w+)\s*(==|!=|>=|<=|>|<)\s*([\d.]+)/);
588
+ if (match) {
589
+ gates.push({
590
+ status: match[1],
591
+ field: match[2],
592
+ operator: match[3],
593
+ value: parseFloat(match[4]),
594
+ line: lineNum
595
+ });
596
+ } else {
597
+ issues.push({ line: lineNum, section: "Gates", message: `Could not parse gate: "${line}"`, severity: "warning" });
598
+ }
599
+ }
600
+ if (gates.length === 0) {
601
+ issues.push({ line: startLine, section: "Gates", message: "No gates found", severity: "error" });
602
+ }
603
+ return gates;
604
+ }
605
+ function parseOutcomes(content, startLine, issues) {
606
+ const outcomes = [];
607
+ const subSections = splitH2Sections(content, startLine);
608
+ for (const sub of subSections) {
609
+ const props = parseKeyValueBullets(sub.content);
610
+ const outcome = {
611
+ id: sub.name,
612
+ type: props.type ?? "number",
613
+ label: props.label ?? sub.name,
614
+ line: sub.startLine
615
+ };
616
+ if (props.range) {
617
+ const rangeParts = props.range.split("-").map(Number);
618
+ if (rangeParts.length === 2 && !isNaN(rangeParts[0]) && !isNaN(rangeParts[1])) {
619
+ outcome.range = [rangeParts[0], rangeParts[1]];
620
+ }
621
+ }
622
+ if (props.display) outcome.display = props.display;
623
+ if (props.primary) outcome.primary = props.primary === "true";
624
+ if (props.assignment) outcome.assignment = props.assignment;
625
+ outcomes.push(outcome);
626
+ }
627
+ return outcomes;
628
+ }
629
+ function splitH2Sections(content, baseStartLine) {
630
+ const lines = content.split("\n");
631
+ const sections = [];
632
+ let current = null;
633
+ const contentLines = [];
634
+ for (let i = 0; i < lines.length; i++) {
635
+ const line = lines[i];
636
+ if (line.startsWith("## ")) {
637
+ if (current) {
638
+ current.content = contentLines.join("\n").trim();
639
+ sections.push(current);
640
+ contentLines.length = 0;
641
+ }
642
+ current = {
643
+ name: line.replace(/^##\s+/, "").trim(),
644
+ content: "",
645
+ startLine: baseStartLine + i + 1
646
+ };
647
+ } else if (current) {
648
+ contentLines.push(line);
649
+ }
650
+ }
651
+ if (current) {
652
+ current.content = contentLines.join("\n").trim();
653
+ sections.push(current);
654
+ }
655
+ return sections;
656
+ }
657
+ function parseKeyValueBullets(content) {
658
+ const result = {};
659
+ for (const line of content.split("\n")) {
660
+ const trimmed = line.trim();
661
+ const match = trimmed.match(/^-\s+(\w[\w\s]*?):\s*(.+)$/);
662
+ if (match) {
663
+ result[match[1].trim().toLowerCase().replace(/\s+/g, "_")] = match[2].trim();
664
+ }
665
+ }
666
+ return result;
667
+ }
668
+ function parseValueLiteral(raw) {
669
+ if (raw === "true") return true;
670
+ if (raw === "false") return false;
671
+ if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("'") && raw.endsWith("'")) {
672
+ return raw.slice(1, -1);
673
+ }
674
+ const num = Number(raw);
675
+ if (!isNaN(num) && raw.trim() !== "") return num;
676
+ return raw;
677
+ }
678
+ function parseWorldMarkdown(markdown) {
679
+ const issues = [];
680
+ const { frontmatter: fmRaw, sections } = splitSections(markdown);
681
+ const frontmatter = parseFrontmatter2(fmRaw, issues);
682
+ const findSection = (name) => sections.find((s) => s.name.toLowerCase() === name.toLowerCase());
683
+ const thesisSection = findSection("Thesis");
684
+ const thesis = thesisSection ? parseThesis(thesisSection.content, thesisSection.startLine, issues) : "";
685
+ if (!thesisSection) {
686
+ issues.push({ line: 0, section: "Thesis", message: "Missing # Thesis section", severity: "error" });
687
+ }
688
+ const invariantsSection = findSection("Invariants");
689
+ const invariants = invariantsSection ? parseInvariants(invariantsSection.content, invariantsSection.startLine, issues) : [];
690
+ if (!invariantsSection) {
691
+ issues.push({ line: 0, section: "Invariants", message: "Missing # Invariants section", severity: "error" });
692
+ }
693
+ const stateSection = findSection("State");
694
+ const stateVariables = stateSection ? parseStateVariables(stateSection.content, stateSection.startLine, issues) : [];
695
+ if (!stateSection) {
696
+ issues.push({ line: 0, section: "State", message: "Missing # State section", severity: "warning" });
697
+ }
698
+ const assumptionsSection = findSection("Assumptions");
699
+ const assumptions = assumptionsSection ? parseAssumptions(assumptionsSection.content, assumptionsSection.startLine, issues) : [];
700
+ if (!assumptionsSection) {
701
+ issues.push({ line: 0, section: "Assumptions", message: "Missing # Assumptions section", severity: "warning" });
702
+ }
703
+ const rulesSection = findSection("Rules");
704
+ const rules = rulesSection ? parseRules(rulesSection.content, rulesSection.startLine, issues) : [];
705
+ if (!rulesSection) {
706
+ issues.push({ line: 0, section: "Rules", message: "Missing # Rules section", severity: "warning" });
707
+ }
708
+ const gatesSection = findSection("Gates");
709
+ const gates = gatesSection ? parseGates(gatesSection.content, gatesSection.startLine, issues) : [];
710
+ if (!gatesSection) {
711
+ issues.push({ line: 0, section: "Gates", message: "Missing # Gates section", severity: "warning" });
712
+ }
713
+ const outcomesSection = findSection("Outcomes");
714
+ const outcomes = outcomesSection ? parseOutcomes(outcomesSection.content, outcomesSection.startLine, issues) : [];
715
+ const parsedSections = sections.map((s) => s.name);
716
+ const knownSections = /* @__PURE__ */ new Set(["thesis", "invariants", "state", "assumptions", "rules", "gates", "outcomes"]);
717
+ for (const section of sections) {
718
+ if (!knownSections.has(section.name.toLowerCase())) {
719
+ issues.push({
720
+ line: section.startLine,
721
+ section: section.name,
722
+ message: `Unrecognized section "${section.name}" \u2014 will be ignored`,
723
+ severity: "info"
724
+ });
725
+ }
726
+ }
727
+ const hasErrors = issues.some((i) => i.severity === "error");
728
+ if (!frontmatter.world_id || !thesis) {
729
+ if (hasErrors) {
730
+ return { world: null, issues };
731
+ }
732
+ }
733
+ return {
734
+ world: {
735
+ frontmatter,
736
+ thesis,
737
+ invariants,
738
+ stateVariables,
739
+ assumptions,
740
+ rules,
741
+ gates,
742
+ outcomes
743
+ },
744
+ issues
745
+ };
746
+ }
747
+ var init_bootstrap_parser = __esm({
748
+ "src/engine/bootstrap-parser.ts"() {
749
+ "use strict";
750
+ }
751
+ });
752
+
753
+ // src/engine/bootstrap-emitter.ts
754
+ var bootstrap_emitter_exports = {};
755
+ __export(bootstrap_emitter_exports, {
756
+ emitWorldDefinition: () => emitWorldDefinition
757
+ });
758
+ function emitWorldDefinition(parsed) {
759
+ const issues = [];
760
+ const fm = parsed.frontmatter;
761
+ const defaultProfile = fm.default_profile ?? parsed.assumptions[0]?.id ?? "baseline";
762
+ const altProfile = fm.alternative_profile ?? parsed.assumptions[1]?.id ?? "alternative";
763
+ const world = {
764
+ world_id: fm.world_id,
765
+ name: fm.name,
766
+ thesis: parsed.thesis,
767
+ version: fm.version ?? "1.0.0",
768
+ runtime_mode: fm.runtime_mode ?? "SIMULATION",
769
+ default_assumption_profile: defaultProfile,
770
+ default_alternative_profile: altProfile,
771
+ modules: parsed.rules.map((r) => r.id),
772
+ players: {
773
+ thinking_space: true,
774
+ experience_space: true,
775
+ action_space: true
776
+ }
777
+ };
778
+ const invariants = parsed.invariants.map((inv) => ({
779
+ id: inv.id,
780
+ label: inv.label,
781
+ enforcement: inv.enforcement === "prompt" ? "prompt" : "structural",
782
+ mutable: false
783
+ }));
784
+ const profiles = {};
785
+ const parameterDefinitions = {};
786
+ for (let i = 0; i < parsed.assumptions.length; i++) {
787
+ const profile = parsed.assumptions[i];
788
+ const params = {};
789
+ for (const [key, val] of Object.entries(profile.parameters)) {
790
+ params[key] = String(val);
791
+ if (!parameterDefinitions[key]) {
792
+ parameterDefinitions[key] = {
793
+ type: typeof val === "boolean" ? "boolean" : typeof val === "number" ? "number" : "enum",
794
+ label: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
795
+ description: `Parameter: ${key}`
796
+ };
797
+ }
798
+ }
799
+ profiles[profile.id] = {
800
+ name: profile.name,
801
+ description: profile.description,
802
+ is_default_baseline: i === 0 || profile.id === defaultProfile,
803
+ is_default_alternative: i === 1 || profile.id === altProfile,
804
+ parameters: params
805
+ };
806
+ }
807
+ const assumptions = { profiles, parameter_definitions: parameterDefinitions };
808
+ const variables = {};
809
+ for (const v of parsed.stateVariables) {
810
+ const stateVar = {
811
+ type: v.type,
812
+ default: v.default,
813
+ mutable: true,
814
+ label: v.label,
815
+ description: v.description
816
+ };
817
+ if (v.type === "number") {
818
+ if (v.min !== void 0) stateVar.min = v.min;
819
+ if (v.max !== void 0) stateVar.max = v.max;
820
+ if (v.step !== void 0) stateVar.step = v.step;
821
+ }
822
+ if (v.type === "enum" && v.options) {
823
+ stateVar.options = v.options;
824
+ }
825
+ variables[v.id] = stateVar;
826
+ }
827
+ const stateSchema = { variables, presets: {} };
828
+ const rules = parsed.rules.map((r) => {
829
+ const triggers = r.triggers.map((t) => ({
830
+ field: t.field,
831
+ operator: t.operator,
832
+ value: t.value,
833
+ source: t.source
834
+ }));
835
+ const effects = r.effects.map((e) => ({
836
+ target: e.target,
837
+ operation: e.operation,
838
+ value: e.value
839
+ }));
840
+ let collapse_check;
841
+ if (r.collapse_check) {
842
+ collapse_check = {
843
+ field: r.collapse_check.field,
844
+ operator: r.collapse_check.operator,
845
+ value: r.collapse_check.value,
846
+ result: "MODEL_COLLAPSES"
847
+ };
848
+ }
849
+ const causal_translation = r.causal_translation ?? {
850
+ trigger_text: "",
851
+ rule_text: "",
852
+ shift_text: "",
853
+ effect_text: ""
854
+ };
855
+ const rule = {
856
+ id: r.id,
857
+ severity: r.severity,
858
+ label: r.label,
859
+ description: r.description ?? r.label,
860
+ order: r.order,
861
+ triggers,
862
+ effects: effects.length > 0 ? effects : void 0,
863
+ collapse_check,
864
+ causal_translation
865
+ };
866
+ return rule;
867
+ });
868
+ const viabilityClassification = parsed.gates.map((g) => {
869
+ const defaults = GATE_DEFAULTS[g.status] ?? { color: "#5c5a52", icon: "\u25CF" };
870
+ return {
871
+ status: g.status,
872
+ field: g.field,
873
+ operator: g.operator,
874
+ value: g.value,
875
+ color: defaults.color,
876
+ icon: defaults.icon
877
+ };
878
+ });
879
+ const gates = {
880
+ viability_classification: viabilityClassification,
881
+ structural_override: {
882
+ description: "Rules with severity=structural and triggered collapse_check force MODEL_COLLAPSES regardless of final margin.",
883
+ enforcement: "mandatory"
884
+ },
885
+ sustainability_threshold: 0.1,
886
+ collapse_visual: {
887
+ background: "#1c1917",
888
+ text: "#fef2f2",
889
+ border: "#b91c1c",
890
+ label: "Structural Failure"
891
+ }
892
+ };
893
+ const computedOutcomes = parsed.outcomes.map((o) => {
894
+ const outcome = {
895
+ id: o.id,
896
+ type: o.type,
897
+ label: o.label,
898
+ show_in_comparison: true
899
+ };
900
+ if (o.range) outcome.range = o.range;
901
+ if (o.display) outcome.display_as = o.display;
902
+ if (o.primary) outcome.primary = o.primary;
903
+ if (o.assignment) outcome.assignment = o.assignment;
904
+ return outcome;
905
+ });
906
+ const outcomes = {
907
+ computed_outcomes: computedOutcomes,
908
+ comparison_layout: {
909
+ primary_card: computedOutcomes.find((o) => o.primary)?.id ?? computedOutcomes[0]?.id ?? "",
910
+ status_badge: "viability_status",
911
+ structural_indicators: rules.filter((r) => r.severity === "structural").map((r) => r.id)
912
+ }
913
+ };
914
+ const metadata = {
915
+ format_version: "1.0.0",
916
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
917
+ last_modified: (/* @__PURE__ */ new Date()).toISOString(),
918
+ authoring_method: "manual-authoring"
919
+ };
920
+ const worldDefinition = {
921
+ world,
922
+ invariants,
923
+ assumptions,
924
+ stateSchema,
925
+ rules,
926
+ gates,
927
+ outcomes,
928
+ metadata
929
+ };
930
+ return { world: worldDefinition, issues };
931
+ }
932
+ var GATE_DEFAULTS;
933
+ var init_bootstrap_emitter = __esm({
934
+ "src/engine/bootstrap-emitter.ts"() {
935
+ "use strict";
936
+ GATE_DEFAULTS = {
937
+ THRIVING: { color: "#0f6b3a", icon: "\u2726" },
938
+ STABLE: { color: "#1856b8", icon: "\u25CF" },
939
+ COMPRESSED: { color: "#a16207", icon: "\u25B2" },
940
+ CRITICAL: { color: "#b91c1c", icon: "\u26A0" },
941
+ MODEL_COLLAPSES: { color: "#7f1d1d", icon: "\u2715" }
942
+ };
261
943
  }
262
944
  });
263
945
 
264
946
  // src/loader/world-loader.ts
265
947
  var world_loader_exports = {};
266
948
  __export(world_loader_exports, {
949
+ DEFAULT_BUNDLED_WORLD: () => DEFAULT_BUNDLED_WORLD,
950
+ loadBundledWorld: () => loadBundledWorld,
267
951
  loadWorld: () => loadWorld,
268
952
  loadWorldFromDirectory: () => loadWorldFromDirectory
269
953
  });
@@ -272,10 +956,18 @@ async function loadWorldFromDirectory(dirPath) {
272
956
  const { join } = await import("path");
273
957
  const { readdirSync } = await import("fs");
274
958
  async function readJson(filename) {
959
+ const filePath = join(dirPath, filename);
275
960
  try {
276
- const content = await readFile(join(dirPath, filename), "utf-8");
961
+ const content = await readFile(filePath, "utf-8");
277
962
  return JSON.parse(content);
278
- } catch {
963
+ } catch (err) {
964
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
965
+ return void 0;
966
+ }
967
+ process.stderr.write(
968
+ `[neuroverse] Warning: Failed to read ${filename}: ${err instanceof Error ? err.message : String(err)}
969
+ `
970
+ );
279
971
  return void 0;
280
972
  }
281
973
  }
@@ -297,10 +989,23 @@ async function loadWorldFromDirectory(dirPath) {
297
989
  const rulesDir = join(dirPath, "rules");
298
990
  const ruleFiles = readdirSync(rulesDir).filter((f) => f.endsWith(".json")).sort();
299
991
  for (const file of ruleFiles) {
300
- const content = await readFile(join(rulesDir, file), "utf-8");
301
- rules.push(JSON.parse(content));
992
+ try {
993
+ const content = await readFile(join(rulesDir, file), "utf-8");
994
+ rules.push(JSON.parse(content));
995
+ } catch (err) {
996
+ process.stderr.write(
997
+ `[neuroverse] Warning: Failed to parse rule ${file}: ${err instanceof Error ? err.message : String(err)}
998
+ `
999
+ );
1000
+ }
1001
+ }
1002
+ } catch (err) {
1003
+ if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) {
1004
+ process.stderr.write(
1005
+ `[neuroverse] Warning: Failed to read rules directory: ${err instanceof Error ? err.message : String(err)}
1006
+ `
1007
+ );
302
1008
  }
303
- } catch {
304
1009
  }
305
1010
  return {
306
1011
  world: worldJson,
@@ -335,14 +1040,49 @@ async function loadWorld(worldPath) {
335
1040
  if (info.isDirectory()) {
336
1041
  return loadWorldFromDirectory(worldPath);
337
1042
  }
338
- if (worldPath.endsWith(".nv-world.zip")) {
339
- throw new Error(".nv-world.zip loading not yet implemented \u2014 use a world directory");
1043
+ throw new Error(`Cannot load world from: ${worldPath} \u2014 expected a directory`);
1044
+ }
1045
+ async function loadBundledWorld(name = DEFAULT_BUNDLED_WORLD) {
1046
+ const { readFile } = await import("fs/promises");
1047
+ const { join, dirname } = await import("path");
1048
+ const { existsSync } = await import("fs");
1049
+ const { fileURLToPath } = await import("url");
1050
+ const { parseWorldMarkdown: parseWorldMarkdown2 } = await Promise.resolve().then(() => (init_bootstrap_parser(), bootstrap_parser_exports));
1051
+ const { emitWorldDefinition: emitWorldDefinition2 } = await Promise.resolve().then(() => (init_bootstrap_emitter(), bootstrap_emitter_exports));
1052
+ const filename = `${name}.nv-world.md`;
1053
+ let packageRoot;
1054
+ try {
1055
+ const thisFile = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import_meta.url));
1056
+ packageRoot = join(thisFile, "..", "..");
1057
+ } catch {
1058
+ packageRoot = process.cwd();
1059
+ }
1060
+ const candidates = [
1061
+ join(packageRoot, "dist", "worlds", filename),
1062
+ join(packageRoot, "src", "worlds", filename)
1063
+ ];
1064
+ for (const candidate of candidates) {
1065
+ if (existsSync(candidate)) {
1066
+ const markdown = await readFile(candidate, "utf-8");
1067
+ const parsed = parseWorldMarkdown2(markdown);
1068
+ if (!parsed.world) {
1069
+ throw new Error(`Failed to parse bundled world: ${candidate}`);
1070
+ }
1071
+ const { world } = emitWorldDefinition2(parsed.world);
1072
+ return world;
1073
+ }
340
1074
  }
341
- throw new Error(`Cannot load world from: ${worldPath} \u2014 expected a directory or .nv-world.zip`);
1075
+ throw new Error(
1076
+ `Bundled world "${name}" not found. Searched:
1077
+ ` + candidates.map((c) => ` ${c}`).join("\n")
1078
+ );
342
1079
  }
1080
+ var import_meta, DEFAULT_BUNDLED_WORLD;
343
1081
  var init_world_loader = __esm({
344
1082
  "src/loader/world-loader.ts"() {
345
1083
  "use strict";
1084
+ import_meta = {};
1085
+ DEFAULT_BUNDLED_WORLD = "coding-agent";
346
1086
  }
347
1087
  });
348
1088
 
@@ -376,7 +1116,44 @@ function evaluateGuard(event, world, options = {}) {
376
1116
  const startTime = performance.now();
377
1117
  const level = options.level ?? "standard";
378
1118
  const includeTrace = options.trace ?? false;
379
- const eventText = (event.intent + " " + (event.tool ?? "") + " " + (event.scope ?? "")).toLowerCase();
1119
+ if (!event.intent || typeof event.intent !== "string") {
1120
+ return {
1121
+ status: "BLOCK",
1122
+ reason: "GuardEvent.intent is required and must be a string",
1123
+ ruleId: "safety-input-validation",
1124
+ evidence: {
1125
+ worldId: world.world?.world_id ?? "",
1126
+ worldName: world.world?.name ?? "",
1127
+ worldVersion: world.world?.version ?? "",
1128
+ evaluatedAt: Date.now(),
1129
+ invariantsSatisfied: 0,
1130
+ invariantsTotal: 0,
1131
+ guardsMatched: [],
1132
+ rulesMatched: [],
1133
+ enforcementLevel: level
1134
+ }
1135
+ };
1136
+ }
1137
+ const inputLength = event.intent.length + (event.tool?.length ?? 0) + (event.scope?.length ?? 0) + (event.payload ? JSON.stringify(event.payload).length : 0);
1138
+ if (inputLength > MAX_INPUT_LENGTH) {
1139
+ return {
1140
+ status: "BLOCK",
1141
+ reason: `Input exceeds maximum allowed length (${MAX_INPUT_LENGTH} characters)`,
1142
+ ruleId: "safety-input-length",
1143
+ evidence: {
1144
+ worldId: world.world?.world_id ?? "",
1145
+ worldName: world.world?.name ?? "",
1146
+ worldVersion: world.world?.version ?? "",
1147
+ evaluatedAt: Date.now(),
1148
+ invariantsSatisfied: 0,
1149
+ invariantsTotal: 0,
1150
+ guardsMatched: [],
1151
+ rulesMatched: [],
1152
+ enforcementLevel: level
1153
+ }
1154
+ };
1155
+ }
1156
+ const eventText = normalizeEventText(event);
380
1157
  const invariantChecks = [];
381
1158
  const safetyChecks = [];
382
1159
  let planCheckResult;
@@ -389,6 +1166,43 @@ function evaluateGuard(event, world, options = {}) {
389
1166
  const guardsMatched = [];
390
1167
  const rulesMatched = [];
391
1168
  checkInvariantCoverage(world, invariantChecks);
1169
+ if (event.roleId && options.agentStates) {
1170
+ const agentState = options.agentStates.get(event.roleId);
1171
+ if (agentState && agentState.cooldownRemaining > 0) {
1172
+ decidingLayer = "safety";
1173
+ decidingId = `penalize-cooldown-${event.roleId}`;
1174
+ const verdict = buildVerdict(
1175
+ "PENALIZE",
1176
+ `Agent "${event.roleId}" is frozen for ${agentState.cooldownRemaining} more round(s) due to prior penalty.`,
1177
+ `penalize-cooldown-${event.roleId}`,
1178
+ void 0,
1179
+ world,
1180
+ level,
1181
+ invariantChecks,
1182
+ guardsMatched,
1183
+ rulesMatched,
1184
+ includeTrace ? buildTrace(
1185
+ invariantChecks,
1186
+ safetyChecks,
1187
+ planCheckResult,
1188
+ roleChecks,
1189
+ guardChecks,
1190
+ kernelRuleChecks,
1191
+ levelChecks,
1192
+ decidingLayer,
1193
+ decidingId,
1194
+ startTime
1195
+ ) : void 0
1196
+ );
1197
+ verdict.intentRecord = {
1198
+ originalIntent: event.intent,
1199
+ finalAction: "blocked (agent frozen)",
1200
+ enforcement: "PENALIZE",
1201
+ consequence: { type: "freeze", rounds: agentState.cooldownRemaining, description: "Agent still in cooldown from prior penalty" }
1202
+ };
1203
+ return verdict;
1204
+ }
1205
+ }
392
1206
  if (options.sessionAllowlist) {
393
1207
  const key = eventToAllowlistKey(event);
394
1208
  if (options.sessionAllowlist.has(key)) {
@@ -516,7 +1330,16 @@ function evaluateGuard(event, world, options = {}) {
516
1330
  if (guardVerdict.status !== "ALLOW") {
517
1331
  decidingLayer = "guard";
518
1332
  decidingId = guardVerdict.ruleId;
519
- return buildVerdict(
1333
+ const intentRecord = {
1334
+ originalIntent: event.intent,
1335
+ 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",
1336
+ ruleApplied: guardVerdict.ruleId,
1337
+ enforcement: guardVerdict.status,
1338
+ modifiedTo: guardVerdict.modifiedTo,
1339
+ consequence: guardVerdict.consequence,
1340
+ reward: guardVerdict.reward
1341
+ };
1342
+ const verdict = buildVerdict(
520
1343
  guardVerdict.status,
521
1344
  guardVerdict.reason,
522
1345
  guardVerdict.ruleId,
@@ -539,6 +1362,10 @@ function evaluateGuard(event, world, options = {}) {
539
1362
  startTime
540
1363
  ) : void 0
541
1364
  );
1365
+ verdict.intentRecord = intentRecord;
1366
+ if (guardVerdict.consequence) verdict.consequence = guardVerdict.consequence;
1367
+ if (guardVerdict.reward) verdict.reward = guardVerdict.reward;
1368
+ return verdict;
542
1369
  }
543
1370
  }
544
1371
  const kernelVerdict = checkKernelRules(eventText, world, kernelRuleChecks, rulesMatched);
@@ -833,6 +1660,21 @@ function checkGuards(event, eventText, world, checks, guardsMatched) {
833
1660
  if (actionMode === "pause") {
834
1661
  return { status: "PAUSE", reason, ruleId: `guard-${guard.id}` };
835
1662
  }
1663
+ if (actionMode === "penalize") {
1664
+ const consequence = guard.consequence ? { ...guard.consequence } : { type: "freeze", rounds: 1, description: `Penalized for violating: ${guard.label}` };
1665
+ return { status: "PENALIZE", reason, ruleId: `guard-${guard.id}`, consequence };
1666
+ }
1667
+ if (actionMode === "reward") {
1668
+ const reward = guard.reward ? { ...guard.reward } : { type: "boost_influence", magnitude: 0.1, description: `Rewarded for: ${guard.label}` };
1669
+ return { status: "REWARD", reason, ruleId: `guard-${guard.id}`, reward };
1670
+ }
1671
+ if (actionMode === "modify") {
1672
+ const modifiedTo = guard.modify_to ?? guard.redirect ?? "hold";
1673
+ return { status: "MODIFY", reason: `${reason} \u2192 Modified to: ${modifiedTo}`, ruleId: `guard-${guard.id}`, modifiedTo };
1674
+ }
1675
+ if (actionMode === "neutral") {
1676
+ return { status: "NEUTRAL", reason, ruleId: `guard-${guard.id}` };
1677
+ }
836
1678
  if (actionMode === "warn" && !warnResult) {
837
1679
  warnResult = { status: "ALLOW", warning: reason, ruleId: `guard-${guard.id}` };
838
1680
  }
@@ -942,9 +1784,7 @@ function checkLevelConstraints(event, level, checks) {
942
1784
  return null;
943
1785
  }
944
1786
  function matchesKeywords(eventText, ruleText) {
945
- const keywords = ruleText.toLowerCase().split(/\s+/).filter((w) => w.length > 3);
946
- if (keywords.length === 0) return false;
947
- return keywords.every((kw) => eventText.includes(kw));
1787
+ return matchesAllKeywords(eventText, ruleText);
948
1788
  }
949
1789
  function eventToAllowlistKey(event) {
950
1790
  return `${(event.tool ?? "*").toLowerCase()}::${event.intent.toLowerCase().trim()}`;
@@ -1005,11 +1845,12 @@ function buildVerdict(status, reason, ruleId, warning, world, level, invariantCh
1005
1845
  if (trace) verdict.trace = trace;
1006
1846
  return verdict;
1007
1847
  }
1008
- var PROMPT_INJECTION_PATTERNS, EXECUTION_CLAIM_PATTERNS, EXECUTION_INTENT_PATTERNS, SCOPE_ESCAPE_PATTERNS, NEUTRAL_MESSAGES;
1848
+ var PROMPT_INJECTION_PATTERNS, EXECUTION_CLAIM_PATTERNS, EXECUTION_INTENT_PATTERNS, SCOPE_ESCAPE_PATTERNS, NEUTRAL_MESSAGES, MAX_INPUT_LENGTH;
1009
1849
  var init_guard_engine = __esm({
1010
1850
  "src/engine/guard-engine.ts"() {
1011
1851
  "use strict";
1012
1852
  init_plan_engine();
1853
+ init_text_utils();
1013
1854
  PROMPT_INJECTION_PATTERNS = [
1014
1855
  // Instruction override
1015
1856
  { pattern: /ignore\s+(previous|all|prior|above)\s+(instructions?|rules?)/i, label: "ignore-instructions" },
@@ -1073,6 +1914,7 @@ var init_guard_engine = __esm({
1073
1914
  "network-mutate": "This action would send data to an external service.",
1074
1915
  "credential-access": "This action would access stored credentials."
1075
1916
  };
1917
+ MAX_INPUT_LENGTH = 1e5;
1076
1918
  }
1077
1919
  });
1078
1920
 
@@ -1247,22 +2089,20 @@ var PLAN_EXIT_CODES = {
1247
2089
  PLAN_COMPLETE: 4
1248
2090
  };
1249
2091
 
2092
+ // src/cli/cli-utils.ts
2093
+ async function readStdin() {
2094
+ const chunks = [];
2095
+ for await (const chunk of process.stdin) {
2096
+ chunks.push(chunk);
2097
+ }
2098
+ return Buffer.concat(chunks).toString("utf-8");
2099
+ }
2100
+
1250
2101
  // src/cli/plan.ts
1251
2102
  function parseArg(args, flag) {
1252
2103
  const idx = args.indexOf(flag);
1253
2104
  return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : void 0;
1254
2105
  }
1255
- function readStdin() {
1256
- return new Promise((resolve, reject) => {
1257
- let data = "";
1258
- process.stdin.setEncoding("utf-8");
1259
- process.stdin.on("data", (chunk) => {
1260
- data += chunk;
1261
- });
1262
- process.stdin.on("end", () => resolve(data));
1263
- process.stdin.on("error", reject);
1264
- });
1265
- }
1266
2106
  async function compileCommand(args) {
1267
2107
  const inputPath = args.find((a) => !a.startsWith("--"));
1268
2108
  if (!inputPath) {