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