@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,624 @@
1
+ import {
2
+ loadConfig
3
+ } from "./chunk-OT6PXH54.js";
4
+ import {
5
+ createProvider
6
+ } from "./chunk-INWQHLPS.js";
7
+ import {
8
+ validateWorld
9
+ } from "./chunk-7P3S7MAY.js";
10
+ import {
11
+ parseWorldMarkdown
12
+ } from "./chunk-EMQDLDAF.js";
13
+ import {
14
+ emitWorldDefinition
15
+ } from "./chunk-PVTQQS3Y.js";
16
+
17
+ // src/engine/derive-normalizer.ts
18
+ function findSections(lines) {
19
+ const sections = [];
20
+ let current = null;
21
+ for (let i = 0; i < lines.length; i++) {
22
+ if (lines[i].startsWith("# ")) {
23
+ if (current) {
24
+ current.end = i;
25
+ sections.push(current);
26
+ }
27
+ current = { name: lines[i].replace(/^#\s+/, "").trim(), start: i, end: lines.length };
28
+ }
29
+ }
30
+ if (current) {
31
+ current.end = lines.length;
32
+ sections.push(current);
33
+ }
34
+ return sections;
35
+ }
36
+ var VALID_INVARIANT_RE = /^-\s+`[^`]+`\s*[—–-]\s*.+/;
37
+ function normalizeInvariantLine(line) {
38
+ const trimmed = line.trim();
39
+ if (!trimmed.startsWith("- ")) return line;
40
+ if (VALID_INVARIANT_RE.test(trimmed)) return line;
41
+ const boldMatch = trimmed.match(/^-\s+\*\*([^*]+)\*\*\s*([—–-])\s*(.+)$/);
42
+ if (boldMatch) {
43
+ const id = boldMatch[1].toLowerCase().replace(/\s+/g, "_");
44
+ const desc = boldMatch[3].trim();
45
+ const hasParens = /\([^)]+\)\s*$/.test(desc);
46
+ return `- \`${id}\` \u2014 ${hasParens ? desc : desc + " (structural, immutable)"}`;
47
+ }
48
+ const snakeMatch = trimmed.match(/^-\s+(\w[\w]*(?:_\w+)+)\s*([—–-])\s*(.+)$/);
49
+ if (snakeMatch) {
50
+ const id = snakeMatch[1];
51
+ const desc = snakeMatch[3].trim();
52
+ const hasParens = /\([^)]+\)\s*$/.test(desc);
53
+ return `- \`${id}\` \u2014 ${hasParens ? desc : desc + " (structural, immutable)"}`;
54
+ }
55
+ const proseMatch = trimmed.match(/^-\s+([A-Z][^(]+?)(?:\s*\(([^)]+)\))?\s*$/);
56
+ if (proseMatch) {
57
+ const desc = proseMatch[1].trim();
58
+ const parens = proseMatch[2] ?? "structural, immutable";
59
+ const id = desc.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "_").slice(0, 50);
60
+ if (id.length >= 3) {
61
+ return `- \`${id}\` \u2014 ${desc} (${parens})`;
62
+ }
63
+ }
64
+ return line;
65
+ }
66
+ var VALID_GATE_RE = /^-\s+\w+:\s*\w+\s*(==|!=|>=|<=|>|<)\s*[\d.]+/;
67
+ var SYMBOLIC_TO_NUMERIC = {
68
+ // Positive states
69
+ full: 100,
70
+ complete: 100,
71
+ total: 100,
72
+ optimal: 95,
73
+ maximum: 100,
74
+ high: 80,
75
+ strong: 80,
76
+ // Mid states
77
+ partial: 60,
78
+ moderate: 50,
79
+ medium: 50,
80
+ growing: 60,
81
+ developing: 50,
82
+ // Low/negative states
83
+ low: 30,
84
+ minimal: 20,
85
+ weak: 20,
86
+ declining: 40,
87
+ limited: 30,
88
+ escalating: 50,
89
+ // Extreme states
90
+ none: 0,
91
+ absent: 0,
92
+ zero: 0,
93
+ critical: 80,
94
+ extreme: 90,
95
+ severe: 85,
96
+ indiscriminate: 80,
97
+ uncontrolled: 90,
98
+ overwhelming: 90
99
+ };
100
+ function normalizeGateLine(line) {
101
+ const trimmed = line.trim();
102
+ if (!trimmed.startsWith("- ")) return line;
103
+ if (VALID_GATE_RE.test(trimmed)) return line;
104
+ const symbolicMatch = trimmed.match(
105
+ /^-\s+(\w+):\s*(\w+)\s*(?:==?)\s*"?([a-zA-Z_]+)"?\s*$/
106
+ );
107
+ if (symbolicMatch) {
108
+ const status = symbolicMatch[1];
109
+ const field = symbolicMatch[2];
110
+ const symbolic = symbolicMatch[3].toLowerCase();
111
+ const numeric = SYMBOLIC_TO_NUMERIC[symbolic];
112
+ if (numeric !== void 0) {
113
+ return `- ${status}: ${field} >= ${numeric}`;
114
+ }
115
+ return `- ${status}: ${field} >= 50`;
116
+ }
117
+ const eqNumMatch = trimmed.match(/^-\s+(\w+):\s*(\w+)\s*=\s*([\d.]+)\s*$/);
118
+ if (eqNumMatch) {
119
+ return `- ${eqNumMatch[1]}: ${eqNumMatch[2]} >= ${eqNumMatch[3]}`;
120
+ }
121
+ return line;
122
+ }
123
+ function normalizeWhenLine(line) {
124
+ const trimmed = line.trim();
125
+ if (!trimmed.startsWith("When ")) return line;
126
+ const parts = trimmed.slice(5).split(/\s+AND\s+/i);
127
+ const normalized = parts.map((part) => {
128
+ const p = part.trim();
129
+ if (/\[(state|assumption)\]\s*$/.test(p)) return p;
130
+ return p + " [state]";
131
+ });
132
+ return "When " + normalized.join(" AND ");
133
+ }
134
+ function normalizeWorldMarkdown(markdown) {
135
+ const lines = markdown.split("\n");
136
+ const sections = findSections(lines);
137
+ const report = { fixCount: 0, invariantIds: 0, gateThresholds: 0, triggerTags: 0 };
138
+ const invariantsSection = sections.find((s) => s.name.toLowerCase() === "invariants");
139
+ const gatesSection = sections.find((s) => s.name.toLowerCase() === "gates");
140
+ const rulesSection = sections.find((s) => s.name.toLowerCase() === "rules");
141
+ for (let i = 0; i < lines.length; i++) {
142
+ const original = lines[i];
143
+ if (invariantsSection && i > invariantsSection.start && i < invariantsSection.end) {
144
+ lines[i] = normalizeInvariantLine(lines[i]);
145
+ if (lines[i] !== original) report.invariantIds++;
146
+ }
147
+ if (gatesSection && i > gatesSection.start && i < gatesSection.end) {
148
+ lines[i] = normalizeGateLine(lines[i]);
149
+ if (lines[i] !== original) report.gateThresholds++;
150
+ }
151
+ if (rulesSection && i > rulesSection.start && i < rulesSection.end) {
152
+ lines[i] = normalizeWhenLine(lines[i]);
153
+ if (lines[i] !== original) report.triggerTags++;
154
+ }
155
+ if (lines[i] !== original) report.fixCount++;
156
+ }
157
+ return { normalized: lines.join("\n"), fixCount: report.fixCount, report };
158
+ }
159
+
160
+ // src/engine/derive-engine.ts
161
+ import { writeFile } from "fs/promises";
162
+
163
+ // src/engine/derive-prompt.ts
164
+ import { readFile } from "fs/promises";
165
+ import { join, dirname } from "path";
166
+ var WORLD_FILENAME = "derivation-world.nv-world.md";
167
+ function getModuleDir() {
168
+ try {
169
+ return dirname(new URL(import.meta.url).pathname);
170
+ } catch {
171
+ return __dirname;
172
+ }
173
+ }
174
+ async function loadDerivationWorld() {
175
+ const moduleDir = getModuleDir();
176
+ const candidates = [
177
+ join(moduleDir, "..", "worlds", WORLD_FILENAME),
178
+ join(moduleDir, "worlds", WORLD_FILENAME)
179
+ ];
180
+ for (const candidate of candidates) {
181
+ try {
182
+ return await readFile(candidate, "utf-8");
183
+ } catch {
184
+ }
185
+ }
186
+ throw new Error(
187
+ `DerivationWorld not found. Searched:
188
+ ${candidates.map((c) => ` - ${c}`).join("\n")}`
189
+ );
190
+ }
191
+ async function collectMarkdownSources(inputPath) {
192
+ const { stat, readFile: rf, readdir } = await import("fs/promises");
193
+ const { join: pathJoin, extname, basename } = await import("path");
194
+ const stats = await stat(inputPath);
195
+ if (stats.isFile()) {
196
+ const content = await rf(inputPath, "utf-8");
197
+ return [{ filename: basename(inputPath), content }];
198
+ }
199
+ if (stats.isDirectory()) {
200
+ const sources = [];
201
+ await collectDir(inputPath, sources, rf, pathJoin, extname, basename);
202
+ sources.sort((a, b) => a.filename.localeCompare(b.filename));
203
+ return sources;
204
+ }
205
+ throw new Error(`Input path is neither a file nor a directory: ${inputPath}`);
206
+ }
207
+ async function collectDir(dir, sources, rf, pathJoin, extname, basename) {
208
+ const { readdir } = await import("fs/promises");
209
+ const entries = await readdir(dir, { withFileTypes: true });
210
+ for (const entry of entries) {
211
+ const fullPath = pathJoin(dir, entry.name);
212
+ if (entry.isDirectory()) {
213
+ await collectDir(fullPath, sources, rf, pathJoin, extname, basename);
214
+ } else if (entry.isFile() && extname(entry.name).toLowerCase() === ".md") {
215
+ const content = await rf(fullPath, "utf-8");
216
+ sources.push({ filename: entry.name, content });
217
+ }
218
+ }
219
+ }
220
+ function concatenateSources(sources) {
221
+ return sources.map((s) => `=== FILE: ${s.filename} ===
222
+ ${s.content}`).join("\n\n");
223
+ }
224
+ var NV_WORLD_SPEC = `
225
+ ## .nv-world.md Format Specification
226
+
227
+ A .nv-world.md file is a structured markdown document with YAML frontmatter and H1 sections.
228
+
229
+ ### Frontmatter (required)
230
+ \`\`\`yaml
231
+ ---
232
+ world_id: <snake_case_id>
233
+ name: <Human Readable Name>
234
+ version: 1.0.0
235
+ ---
236
+ \`\`\`
237
+
238
+ ### Required Sections
239
+
240
+ # Thesis
241
+ A single paragraph stating the structural claim this world tests. Must be testable and falsifiable.
242
+
243
+ # Invariants
244
+ Bullet list of non-negotiable constraints.
245
+
246
+ STRICT FORMAT \u2014 Invariant IDs MUST be wrapped in backticks. Every bullet MUST follow this exact pattern:
247
+ - \\\`invariant_id\\\` \u2014 Description text (enforcement, mutability)
248
+
249
+ VALID examples:
250
+ - \\\`rage_manifestation\\\` \u2014 Suppressed rage manifests as a physical monster (structural, immutable)
251
+ - \\\`healing_requires_integration\\\` \u2014 Recovery requires emotional integration (operational, immutable)
252
+
253
+ INVALID examples (these WILL cause parse failures):
254
+ - rage_manifestation \u2014 Suppressed rage manifests as a monster
255
+ - Suppressed rage manifests as a monster (structural, immutable)
256
+ - **rage_manifestation** \u2014 Description
257
+
258
+ Rules:
259
+ - The ID inside backticks must be snake_case (lowercase with underscores)
260
+ - Use "structural" for constraints derived directly from source material
261
+ - Use "operational" for constraints you inferred
262
+ - Mutability is almost always "immutable"
263
+
264
+ # State
265
+ H2 sub-sections, each defining a state variable:
266
+ ## variable_name
267
+ - type: number | enum | boolean
268
+ - min: <number> (for number type)
269
+ - max: <number> (for number type)
270
+ - step: <number> (for number type)
271
+ - options: option_a, option_b (for enum type)
272
+ - default: <value>
273
+ - label: Human Label
274
+ - description: What this variable represents
275
+
276
+ IMPORTANT: State variable IDs (the ## heading) must be snake_case. The "default" value MUST be numeric for number types and MUST be one of the declared options for enum types.
277
+
278
+ # Assumptions
279
+ H2 sub-sections, each defining a scenario profile:
280
+ ## profile_id
281
+ - name: Profile Name
282
+ - description: What this profile represents
283
+ - param_key: param_value
284
+
285
+ # Rules
286
+ H2 sub-sections with this format:
287
+ ## rule-001: Rule Label (structural|degradation|advantage)
288
+ Single sentence description.
289
+
290
+ When field == "value" [state] AND other_field > 50 [state]
291
+ Then target *= 0.30, other_target = false
292
+ Collapse: field < 0.05
293
+
294
+ > trigger: What triggers this rule
295
+ > rule: What the rule means
296
+ > shift: What changes
297
+ > effect: The concrete effect
298
+
299
+ Rules must have:
300
+ - A "When" line with triggers referencing [state] or [assumption] sources
301
+ - A "Then" line with effects using =, *=, +=, or -= operators
302
+ - Optional "Collapse:" line for failure conditions
303
+
304
+ STRICT FORMAT for triggers \u2014 each trigger MUST match: field_name <operator> <value> [state|assumption]
305
+ - Operators: ==, !=, >=, <=, >, <
306
+ - Values must be numeric (50), boolean (true/false), or quoted strings ("value")
307
+ - Source tag [state] or [assumption] is REQUIRED
308
+
309
+ STRICT FORMAT for effects \u2014 each effect MUST match: target_field <operator> <value>
310
+ - Operators: =, *=, +=, -=
311
+ - Values must be numeric (0.30), boolean (true/false), or quoted strings ("value")
312
+
313
+ # Gates
314
+ Bullet list of status thresholds (must be monotonically decreasing).
315
+
316
+ STRICT FORMAT \u2014 Gate thresholds MUST be numeric. Symbolic values like "full", "partial", "escalating" are NOT allowed. Every gate MUST follow this exact pattern:
317
+ - STATUS_NAME: field_name >= <number>
318
+
319
+ VALID examples:
320
+ - BEST_STATUS: integration_level >= 90
321
+ - GOOD_STATUS: integration_level >= 60
322
+ - WARN_STATUS: monster_rage >= 40
323
+ - BAD_STATUS: monster_rage >= 70
324
+ - WORST_STATUS: josie_endangerment >= 90
325
+
326
+ INVALID examples (these WILL cause parse failures):
327
+ - BEST_STATUS: integration = full
328
+ - GOOD_STATUS: integration = partial
329
+ - BEST_STATUS: true_integration_state == "complete"
330
+
331
+ Rules:
332
+ - All gate thresholds must be NUMERIC values (integers or decimals)
333
+ - The field_name must reference a declared State variable or Outcome
334
+ - Operators: >=, <=, >, <, ==, !=
335
+ - Status names should be uppercase with underscores
336
+ - Thresholds must be monotonically decreasing from best to worst status
337
+
338
+ # Outcomes
339
+ H2 sub-sections defining computed outcomes:
340
+ ## outcome_id
341
+ - type: number | enum | boolean
342
+ - range: 0-100 (for numbers)
343
+ - display: percentage | integer | decimal
344
+ - label: Human Label
345
+ - primary: true (for the main metric)
346
+ `.trim();
347
+ async function buildSystemPrompt() {
348
+ const derivationWorld = await loadDerivationWorld();
349
+ const invariantLines = derivationWorld.split("\n").filter((l) => l.trim().startsWith("- `")).map((l) => {
350
+ const match = l.match(/^-\s+`([^`]+)`\s*[—–-]\s*(.+?)(?:\s*\([^)]+\))?\s*$/);
351
+ return match ? `- ${match[2].trim()}` : null;
352
+ }).filter(Boolean);
353
+ return `You are a governance document synthesizer for NeuroVerse OS.
354
+
355
+ Your task: Given arbitrary markdown source material, synthesize a valid .nv-world.md governance document.
356
+
357
+ ${NV_WORLD_SPEC}
358
+
359
+ ## Synthesis Constraints (from DerivationWorld)
360
+
361
+ You MUST follow these constraints:
362
+ ${invariantLines.join("\n")}
363
+
364
+ ## Critical Rules
365
+
366
+ 1. Output ONLY the .nv-world.md document. No preamble, no explanation, no trailing commentary.
367
+ 2. Do not wrap the output in a code fence.
368
+ 3. Every invariant derived from explicit source statements must be marked (structural, immutable).
369
+ 4. Every invariant you infer that is not directly stated in the source must be marked (operational, immutable).
370
+ 5. All state variables, rules, and invariants must trace to concepts present in the input.
371
+ 6. Do not invent governance domains beyond what the source material covers.
372
+ 7. Every rule must have a When trigger line and a Then effect line.
373
+ 8. Gate thresholds must be monotonically decreasing from best to worst status.
374
+ 9. The frontmatter must include world_id, name, and version.
375
+ 10. Rule descriptions must be a single sentence.
376
+
377
+ ## Syntax Precision (CRITICAL)
378
+
379
+ The output is parsed by a deterministic regex parser. If the syntax is wrong, the parse FAILS.
380
+
381
+ INVARIANTS: Every invariant bullet MUST use backtick-wrapped IDs:
382
+ CORRECT: - \\\`my_invariant_id\\\` \u2014 Description (structural, immutable)
383
+ WRONG: - my_invariant_id \u2014 Description
384
+
385
+ GATES: Every gate MUST use NUMERIC thresholds:
386
+ CORRECT: - THRIVING: score >= 80
387
+ WRONG: - THRIVING: state = optimal
388
+
389
+ TRIGGERS: Every trigger MUST end with [state] or [assumption]:
390
+ CORRECT: When score < 25 [state]
391
+ WRONG: When score < 25
392
+
393
+ EFFECTS: Every effect MUST use a recognized operator:
394
+ CORRECT: Then score *= 0.50, active = false
395
+ WRONG: Then score decreases by half`;
396
+ }
397
+ function buildUserPrompt(concatenatedMarkdown) {
398
+ return `Synthesize a valid .nv-world.md under DerivationWorld constraints from the following source material.
399
+
400
+ Output ONLY the .nv-world.md content. Start with the --- frontmatter delimiter.
401
+
402
+ Source material:
403
+
404
+ ${concatenatedMarkdown}`;
405
+ }
406
+
407
+ // src/engine/derive-engine.ts
408
+ function extractWorldMarkdown(raw) {
409
+ let content = raw.trim();
410
+ const fenceMatch = content.match(/```(?:markdown|md)?\s*\n([\s\S]*?)```/);
411
+ if (fenceMatch) {
412
+ content = fenceMatch[1].trim();
413
+ }
414
+ const sentinelMatch = content.match(
415
+ /(?:BEGIN NV WORLD|BEGIN_NV_WORLD)[\s\n]*([\s\S]*?)[\s\n]*(?:END NV WORLD|END_NV_WORLD)/i
416
+ );
417
+ if (sentinelMatch) {
418
+ content = sentinelMatch[1].trim();
419
+ }
420
+ if (!content.startsWith("---")) {
421
+ const fmIndex = content.indexOf("---\n");
422
+ if (fmIndex >= 0) {
423
+ content = content.slice(fmIndex);
424
+ }
425
+ }
426
+ if (!content.startsWith("---") && /^# /m.test(content)) {
427
+ const generated = generateFrontmatter(content);
428
+ content = generated + "\n" + content;
429
+ }
430
+ if (!content.startsWith("---")) return null;
431
+ const fmEnd = content.indexOf("---", 3);
432
+ if (fmEnd === -1) return null;
433
+ const frontmatter = content.slice(3, fmEnd);
434
+ if (!frontmatter.includes("world_id:")) return null;
435
+ return content;
436
+ }
437
+ function generateFrontmatter(content) {
438
+ let name = "Derived World";
439
+ const thesisMatch = content.match(/^# Thesis\s*\n+(.+)/m);
440
+ if (thesisMatch) {
441
+ const firstSentence = thesisMatch[1].replace(/[.!?].*$/, "").trim();
442
+ if (firstSentence.length >= 3 && firstSentence.length <= 60) {
443
+ name = firstSentence;
444
+ }
445
+ }
446
+ const worldId = name.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "_").slice(0, 50);
447
+ return [
448
+ "---",
449
+ `world_id: ${worldId}`,
450
+ `name: ${name}`,
451
+ "version: 0.1",
452
+ "runtime_mode: simulation",
453
+ "---"
454
+ ].join("\n");
455
+ }
456
+ var GATES = [
457
+ { status: "FAITHFUL", threshold: 0.85 },
458
+ { status: "USABLE", threshold: 0.6 },
459
+ { status: "REVIEWABLE", threshold: 0.4 },
460
+ { status: "SUSPECT", threshold: 0.15 },
461
+ { status: "DERIVATION_REJECTED", threshold: 0 }
462
+ ];
463
+ function classifyGate(errors, warnings, sectionCount) {
464
+ const maxSections = 7;
465
+ const completeness = sectionCount / maxSections;
466
+ const fidelity = errors === 0 ? Math.max(0, completeness - warnings * 0.05) : 0;
467
+ for (const gate of GATES) {
468
+ if (fidelity >= gate.threshold) return gate.status;
469
+ }
470
+ return "DERIVATION_REJECTED";
471
+ }
472
+ async function deriveWorld(options) {
473
+ const startTime = performance.now();
474
+ const sources = await collectMarkdownSources(options.inputPath);
475
+ if (sources.length === 0) {
476
+ throw new DeriveInputError("No markdown files found in input path");
477
+ }
478
+ const concatenated = concatenateSources(sources);
479
+ const systemPrompt = await buildSystemPrompt();
480
+ const userPrompt = buildUserPrompt(concatenated);
481
+ if (options.dryRun) {
482
+ return {
483
+ result: {
484
+ success: true,
485
+ outputPath: options.outputPath,
486
+ sectionsDetected: [],
487
+ validationErrors: 0,
488
+ validationWarnings: 0,
489
+ findings: [],
490
+ gate: "DRY_RUN",
491
+ durationMs: performance.now() - startTime
492
+ },
493
+ exitCode: 0,
494
+ dryRunOutput: { systemPrompt, userPrompt }
495
+ };
496
+ }
497
+ const savedConfig = await loadConfig();
498
+ const config = {
499
+ provider: options.providerOverride?.provider ?? savedConfig?.provider ?? "",
500
+ model: options.providerOverride?.model ?? savedConfig?.model ?? "",
501
+ apiKey: options.providerOverride?.apiKey ?? savedConfig?.apiKey ?? "",
502
+ endpoint: options.providerOverride?.endpoint ?? savedConfig?.endpoint ?? null
503
+ };
504
+ if (!config.apiKey) {
505
+ throw new DeriveProviderError("No API key configured. Run: neuroverse configure-ai");
506
+ }
507
+ if (!config.model) {
508
+ throw new DeriveProviderError("No model configured. Run: neuroverse configure-ai");
509
+ }
510
+ const provider = createProvider(config);
511
+ let rawResponse;
512
+ try {
513
+ rawResponse = await provider.complete(systemPrompt, userPrompt);
514
+ } catch (e) {
515
+ throw new DeriveProviderError(`AI provider failed: ${e instanceof Error ? e.message : String(e)}`);
516
+ }
517
+ const extracted = extractWorldMarkdown(rawResponse);
518
+ if (!extracted) {
519
+ throw new DeriveProviderError(
520
+ "Could not extract valid .nv-world.md from AI response. Response must contain frontmatter with world_id."
521
+ );
522
+ }
523
+ const { normalized, fixCount, report: normReport } = normalizeWorldMarkdown(extracted);
524
+ const { world, issues } = parseWorldMarkdown(normalized);
525
+ const errors = issues.filter((i) => i.severity === "error");
526
+ const warnings = issues.filter((i) => i.severity === "warning");
527
+ const sectionsDetected = world ? Object.keys(world).filter((k) => {
528
+ const val = world[k];
529
+ if (Array.isArray(val)) return val.length > 0;
530
+ if (typeof val === "string") return val.length > 0;
531
+ return !!val;
532
+ }) : [];
533
+ if (world && options.validate) {
534
+ try {
535
+ const { world: worldDef } = emitWorldDefinition(world);
536
+ const report = validateWorld(worldDef);
537
+ for (const finding of report.findings) {
538
+ if (finding.severity === "error" || finding.severity === "warning") {
539
+ issues.push({
540
+ line: 0,
541
+ section: `Validate:${finding.category}`,
542
+ message: finding.message,
543
+ severity: finding.severity
544
+ });
545
+ }
546
+ }
547
+ } catch {
548
+ }
549
+ }
550
+ const allErrors = issues.filter((i) => i.severity === "error");
551
+ const allWarnings = issues.filter((i) => i.severity === "warning");
552
+ const gate = classifyGate(allErrors.length, allWarnings.length, sectionsDetected.length);
553
+ const findings = issues.filter((i) => i.severity === "error" || i.severity === "warning").map((i) => ({
554
+ severity: i.severity,
555
+ section: i.section,
556
+ message: i.message,
557
+ line: i.line
558
+ }));
559
+ let output = normalized;
560
+ if (findings.length > 0 || fixCount > 0) {
561
+ const lines = [`<!-- DERIVATION STATUS: ${gate}`];
562
+ if (fixCount > 0) {
563
+ const details = [];
564
+ if (normReport.invariantIds > 0) details.push(`${normReport.invariantIds} invariant ID(s) wrapped`);
565
+ if (normReport.gateThresholds > 0) details.push(`${normReport.gateThresholds} gate threshold(s) converted`);
566
+ if (normReport.triggerTags > 0) details.push(`${normReport.triggerTags} trigger(s) tagged with [state]`);
567
+ lines.push(``, `Normalizer: ${fixCount} fix(es) applied`);
568
+ for (const d of details) lines.push(` - ${d}`);
569
+ }
570
+ const errs = findings.filter((f) => f.severity === "error");
571
+ const warns = findings.filter((f) => f.severity === "warning");
572
+ if (errs.length > 0) {
573
+ lines.push("", "Errors:");
574
+ for (const f of errs) lines.push(`- [${f.section}] ${f.message}`);
575
+ }
576
+ if (warns.length > 0) {
577
+ lines.push("", "Warnings:");
578
+ for (const f of warns) lines.push(`- [${f.section}] ${f.message}`);
579
+ }
580
+ lines.push("-->", "");
581
+ output = lines.join("\n") + normalized;
582
+ }
583
+ await writeFile(options.outputPath, output, "utf-8");
584
+ const hasErrors = allErrors.length > 0;
585
+ return {
586
+ result: {
587
+ success: !hasErrors,
588
+ outputPath: options.outputPath,
589
+ sectionsDetected,
590
+ validationErrors: allErrors.length,
591
+ validationWarnings: allWarnings.length,
592
+ findings,
593
+ gate,
594
+ normalization: fixCount > 0 ? {
595
+ fixCount: normReport.fixCount,
596
+ invariantIds: normReport.invariantIds,
597
+ gateThresholds: normReport.gateThresholds,
598
+ triggerTags: normReport.triggerTags
599
+ } : void 0,
600
+ durationMs: performance.now() - startTime
601
+ },
602
+ exitCode: hasErrors ? 1 : 0
603
+ };
604
+ }
605
+ var DeriveInputError = class extends Error {
606
+ constructor(message) {
607
+ super(message);
608
+ this.name = "DeriveInputError";
609
+ }
610
+ };
611
+ var DeriveProviderError = class extends Error {
612
+ constructor(message) {
613
+ super(message);
614
+ this.name = "DeriveProviderError";
615
+ }
616
+ };
617
+
618
+ export {
619
+ normalizeWorldMarkdown,
620
+ extractWorldMarkdown,
621
+ deriveWorld,
622
+ DeriveInputError,
623
+ DeriveProviderError
624
+ };