@neuroverseos/governance 0.8.0 → 0.8.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.
@@ -6,17 +6,29 @@ import {
6
6
  classifyActorDomain,
7
7
  classifyEvents,
8
8
  composeSystemPrompt,
9
+ compressExocortex,
10
+ compressLens,
11
+ compressPriorReads,
12
+ compressWorldmodel,
9
13
  computePersistence,
10
14
  createAnthropicAI,
11
15
  createMockAI,
12
16
  createMockGitHubAdapter,
17
+ discoverWorlds,
13
18
  emergent,
14
19
  extractSignals,
20
+ fetchDiscordActivity,
15
21
  fetchGitHubActivity,
16
22
  fetchGitHubOrgActivity,
23
+ fetchNotionActivity,
24
+ fetchSlackActivity,
25
+ formatActiveWorlds,
26
+ formatDiscordSignalsForPrompt,
17
27
  formatExocortexForPrompt,
28
+ formatNotionSignalsForPrompt,
18
29
  formatPriorReadsForPrompt,
19
30
  formatScope,
31
+ formatSlackSignalsForPrompt,
20
32
  formatTeamExocorticesForPrompt,
21
33
  interpretPatterns,
22
34
  isPresent,
@@ -37,412 +49,19 @@ import {
37
49
  think,
38
50
  updateKnowledge,
39
51
  writeRead
40
- } from "../chunk-MC6O5GV5.js";
52
+ } from "../chunk-ETDIEVAX.js";
41
53
  import {
42
54
  LENSES,
43
55
  aukiBuilderLens,
44
56
  getLens,
45
- listLenses
46
- } from "../chunk-VGFDMPVB.js";
57
+ listLenses,
58
+ sovereignConduitLens
59
+ } from "../chunk-F2LWMOM5.js";
47
60
  import "../chunk-I4RTIMLX.js";
48
61
  import "../chunk-ZAF6JH23.js";
49
62
  import "../chunk-QLPTHTVB.js";
50
63
  import "../chunk-QWGCMQQD.js";
51
64
 
52
- // src/radiant/adapters/discord.ts
53
- async function fetchDiscordActivity(guildId, token, options = {}) {
54
- const windowDays = options.windowDays ?? 14;
55
- const perChannel = options.perChannel ?? 100;
56
- const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
57
- const headers = {
58
- Authorization: `Bot ${token}`,
59
- "Content-Type": "application/json"
60
- };
61
- const channels = await fetchJSON(
62
- `https://discord.com/api/v10/guilds/${guildId}/channels`,
63
- headers
64
- );
65
- const textChannels = channels.filter((c) => {
66
- if (c.type !== 0) return false;
67
- if (options.channelIds && options.channelIds.length > 0) {
68
- return options.channelIds.includes(c.id);
69
- }
70
- if (options.visibility === "public") {
71
- return !c.name.startsWith("private-") && !c.nsfw;
72
- }
73
- return true;
74
- });
75
- const events = [];
76
- let totalMessages = 0;
77
- let helpRequests = 0;
78
- let unresolvedThreads = 0;
79
- let newcomerMessages = 0;
80
- const responseTimes = [];
81
- const participants = /* @__PURE__ */ new Set();
82
- const knownParticipants = /* @__PURE__ */ new Set();
83
- const topicCounts = /* @__PURE__ */ new Map();
84
- for (const channel of textChannels.slice(0, 15)) {
85
- try {
86
- const messages = await fetchJSON(
87
- `https://discord.com/api/v10/channels/${channel.id}/messages?limit=${perChannel}`,
88
- headers
89
- );
90
- const inWindow = messages.filter(
91
- (m) => new Date(m.timestamp) >= since
92
- );
93
- totalMessages += inWindow.length;
94
- const topic = channel.name.replace(/-/g, " ");
95
- topicCounts.set(topic, (topicCounts.get(topic) ?? 0) + inWindow.length);
96
- for (const msg of inWindow) {
97
- const actor = mapDiscordUser(msg.author);
98
- participants.add(actor.id);
99
- const lowerContent = msg.content.toLowerCase();
100
- if (lowerContent.includes("help") || lowerContent.includes("stuck") || lowerContent.includes("how do i") || lowerContent.includes("anyone know")) {
101
- helpRequests++;
102
- }
103
- if (msg.referenced_message) {
104
- const refTime = new Date(msg.referenced_message.timestamp).getTime();
105
- const msgTime = new Date(msg.timestamp).getTime();
106
- const diffMinutes = (msgTime - refTime) / 6e4;
107
- if (diffMinutes > 0 && diffMinutes < 10080) {
108
- responseTimes.push(diffMinutes);
109
- }
110
- }
111
- events.push({
112
- id: `discord-${msg.id}`,
113
- timestamp: msg.timestamp,
114
- actor,
115
- kind: "discord_message",
116
- content: msg.content.slice(0, 500),
117
- respondsTo: msg.referenced_message ? {
118
- eventId: `discord-${msg.referenced_message.id}`,
119
- actor: mapDiscordUser(msg.referenced_message.author)
120
- } : void 0,
121
- metadata: {
122
- channel: channel.name,
123
- guildId
124
- }
125
- });
126
- }
127
- } catch {
128
- }
129
- }
130
- const avgResponseMinutes = responseTimes.length > 0 ? responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length : null;
131
- const topTopics = [...topicCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([t]) => t);
132
- const signals = {
133
- totalMessages,
134
- activeChannels: textChannels.length,
135
- uniqueParticipants: participants.size,
136
- avgResponseMinutes: avgResponseMinutes ? Math.round(avgResponseMinutes) : null,
137
- helpRequests,
138
- unresolvedThreads,
139
- topTopics,
140
- newcomerMessages
141
- };
142
- events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
143
- return { events, signals };
144
- }
145
- function formatDiscordSignalsForPrompt(signals) {
146
- if (signals.totalMessages === 0) return "";
147
- const lines = [
148
- "## Discord Activity (conversational behavior)",
149
- "",
150
- `${signals.totalMessages} messages across ${signals.activeChannels} channels.`,
151
- `${signals.uniqueParticipants} unique participants.`
152
- ];
153
- if (signals.avgResponseMinutes !== null) {
154
- lines.push(`Average response time: ${signals.avgResponseMinutes} minutes.`);
155
- }
156
- if (signals.helpRequests > 0) {
157
- lines.push(`${signals.helpRequests} help requests detected.`);
158
- }
159
- if (signals.unresolvedThreads > 0) {
160
- lines.push(`${signals.unresolvedThreads} unresolved threads.`);
161
- }
162
- if (signals.topTopics.length > 0) {
163
- lines.push(`Top discussion topics: ${signals.topTopics.join(", ")}.`);
164
- }
165
- lines.push("");
166
- lines.push("Compare conversational activity against GitHub shipping activity.");
167
- lines.push("Where debates happen in Discord but nothing ships in GitHub, name the gap.");
168
- lines.push("Where work ships in GitHub but nobody discusses it in Discord, name the visibility gap.");
169
- return lines.join("\n");
170
- }
171
- function mapDiscordUser(user) {
172
- return {
173
- id: user.username,
174
- kind: user.bot ? "bot" : "human",
175
- name: user.username
176
- };
177
- }
178
- async function fetchJSON(url, headers) {
179
- const res = await fetch(url, { headers });
180
- if (!res.ok) {
181
- if (res.status === 404 || res.status === 403) return [];
182
- throw new Error(`Discord API error ${res.status}: ${(await res.text()).slice(0, 300)}`);
183
- }
184
- return await res.json();
185
- }
186
-
187
- // src/radiant/adapters/slack.ts
188
- async function fetchSlackActivity(token, options = {}) {
189
- const windowDays = options.windowDays ?? 14;
190
- const perChannel = options.perChannel ?? 100;
191
- const oldest = String(
192
- Math.floor((Date.now() - windowDays * 24 * 60 * 60 * 1e3) / 1e3)
193
- );
194
- const headers = {
195
- Authorization: `Bearer ${token}`,
196
- "Content-Type": "application/json"
197
- };
198
- const channelsResponse = await fetchSlackAPI("https://slack.com/api/conversations.list?types=public_channel&limit=200", headers);
199
- let channels = channelsResponse.channels ?? [];
200
- if (options.channelIds && options.channelIds.length > 0) {
201
- const ids = new Set(options.channelIds);
202
- channels = channels.filter((c) => ids.has(c.id));
203
- }
204
- if (options.visibility === "public") {
205
- channels = channels.filter((c) => !c.is_private && !c.is_archived);
206
- }
207
- const events = [];
208
- let totalMessages = 0;
209
- let reactionCount = 0;
210
- let unresolvedThreads = 0;
211
- const responseTimes = [];
212
- const participants = /* @__PURE__ */ new Set();
213
- const externalParticipants = /* @__PURE__ */ new Set();
214
- const channelMessageCounts = /* @__PURE__ */ new Map();
215
- for (const channel of channels.slice(0, 15)) {
216
- try {
217
- const historyResponse = await fetchSlackAPI(
218
- `https://slack.com/api/conversations.history?channel=${channel.id}&limit=${perChannel}&oldest=${oldest}`,
219
- headers
220
- );
221
- const messages = historyResponse.messages ?? [];
222
- totalMessages += messages.length;
223
- channelMessageCounts.set(channel.name, messages.length);
224
- for (const msg of messages) {
225
- if (msg.subtype === "channel_join" || msg.subtype === "channel_leave") continue;
226
- const actor = mapSlackUser(msg.user ?? "unknown");
227
- participants.add(actor.id);
228
- if (msg.reactions) {
229
- reactionCount += msg.reactions.reduce(
230
- (sum, r) => sum + (r.count ?? 0),
231
- 0
232
- );
233
- }
234
- if (msg.thread_ts && msg.thread_ts !== msg.ts) {
235
- const parentTs = parseFloat(msg.thread_ts) * 1e3;
236
- const msgTs = parseFloat(msg.ts) * 1e3;
237
- const diffMinutes = (msgTs - parentTs) / 6e4;
238
- if (diffMinutes > 0 && diffMinutes < 10080) {
239
- responseTimes.push(diffMinutes);
240
- }
241
- }
242
- if (msg.thread_ts === msg.ts && (!msg.reply_count || msg.reply_count === 0)) {
243
- if (msg.text && (msg.text.includes("?") || msg.text.toLowerCase().includes("help"))) {
244
- unresolvedThreads++;
245
- }
246
- }
247
- const timestamp = new Date(parseFloat(msg.ts) * 1e3).toISOString();
248
- events.push({
249
- id: `slack-${msg.ts}`,
250
- timestamp,
251
- actor,
252
- kind: "slack_message",
253
- content: (msg.text ?? "").slice(0, 500),
254
- respondsTo: msg.thread_ts && msg.thread_ts !== msg.ts ? {
255
- eventId: `slack-${msg.thread_ts}`,
256
- actor: { id: "thread-parent", kind: "unknown" }
257
- } : void 0,
258
- metadata: {
259
- channel: channel.name,
260
- isPrivate: channel.is_private,
261
- hasReactions: (msg.reactions?.length ?? 0) > 0
262
- }
263
- });
264
- }
265
- } catch {
266
- }
267
- }
268
- const avgResponseMinutes = responseTimes.length > 0 ? Math.round(responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length) : null;
269
- const topChannels = [...channelMessageCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([name]) => name);
270
- const signals = {
271
- totalMessages,
272
- activeChannels: channelMessageCounts.size,
273
- uniqueParticipants: participants.size,
274
- avgResponseMinutes,
275
- externalParticipants: externalParticipants.size,
276
- unresolvedThreads,
277
- topChannels,
278
- reactionCount
279
- };
280
- events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
281
- return { events, signals };
282
- }
283
- function formatSlackSignalsForPrompt(signals) {
284
- if (signals.totalMessages === 0) return "";
285
- const lines = [
286
- "## Slack Activity (external coordination)",
287
- "",
288
- `${signals.totalMessages} messages across ${signals.activeChannels} channels.`,
289
- `${signals.uniqueParticipants} unique participants.`
290
- ];
291
- if (signals.avgResponseMinutes !== null) {
292
- lines.push(`Average thread response time: ${signals.avgResponseMinutes} minutes.`);
293
- }
294
- if (signals.unresolvedThreads > 0) {
295
- lines.push(`${signals.unresolvedThreads} questions/threads with no reply.`);
296
- }
297
- if (signals.reactionCount > 0) {
298
- lines.push(`${signals.reactionCount} reactions (engagement signal).`);
299
- }
300
- if (signals.topChannels.length > 0) {
301
- lines.push(`Most active channels: ${signals.topChannels.join(", ")}.`);
302
- }
303
- lines.push("");
304
- lines.push("Slack carries external coordination \u2014 partner and client communication.");
305
- lines.push("Compare partner engagement against internal activity. Where partners are");
306
- lines.push("active but internal follow-through is low, name the gap.");
307
- return lines.join("\n");
308
- }
309
- function mapSlackUser(userId) {
310
- return {
311
- id: userId,
312
- kind: "human",
313
- name: userId
314
- };
315
- }
316
- async function fetchSlackAPI(url, headers) {
317
- const res = await fetch(url, { headers });
318
- if (!res.ok) {
319
- throw new Error(`Slack API error ${res.status}: ${(await res.text()).slice(0, 300)}`);
320
- }
321
- const data = await res.json();
322
- if (!data.ok) {
323
- throw new Error(`Slack API error: ${data.error ?? "unknown"}`);
324
- }
325
- return data;
326
- }
327
-
328
- // src/radiant/adapters/notion.ts
329
- async function fetchNotionActivity(token, options = {}) {
330
- const windowDays = options.windowDays ?? 14;
331
- const maxPages = options.maxPages ?? 100;
332
- const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
333
- const headers = {
334
- Authorization: `Bearer ${token}`,
335
- "Notion-Version": "2022-06-28",
336
- "Content-Type": "application/json"
337
- };
338
- const searchResponse = await fetchNotionAPI("https://api.notion.com/v1/search", headers, {
339
- method: "POST",
340
- body: JSON.stringify({
341
- filter: { property: "object", value: "page" },
342
- sort: { direction: "descending", timestamp: "last_edited_time" },
343
- page_size: maxPages
344
- })
345
- });
346
- const pages = searchResponse.results ?? [];
347
- const events = [];
348
- const editors = /* @__PURE__ */ new Set();
349
- let pagesCreated = 0;
350
- let pagesUpdated = 0;
351
- let stalePages = 0;
352
- const editAges = [];
353
- const topPages = [];
354
- const now = Date.now();
355
- for (const page of pages) {
356
- const lastEdited = new Date(page.last_edited_time);
357
- const created = new Date(page.created_time);
358
- const daysSinceEdit = (now - lastEdited.getTime()) / (24 * 60 * 60 * 1e3);
359
- editAges.push(daysSinceEdit);
360
- if (daysSinceEdit > 30) stalePages++;
361
- const title = extractTitle(page);
362
- const editorId = page.last_edited_by?.id ?? "unknown";
363
- editors.add(editorId);
364
- if (lastEdited >= since) {
365
- const isNew = created >= since;
366
- if (isNew) pagesCreated++;
367
- else pagesUpdated++;
368
- topPages.push({ title, editedAt: page.last_edited_time });
369
- events.push({
370
- id: `notion-${page.id}`,
371
- timestamp: page.last_edited_time,
372
- actor: {
373
- id: editorId,
374
- kind: "human",
375
- name: editorId
376
- },
377
- kind: isNew ? "doc_created" : "doc_updated",
378
- content: `${isNew ? "Created" : "Updated"}: ${title}`,
379
- metadata: {
380
- pageId: page.id,
381
- url: page.url,
382
- createdAt: page.created_time
383
- }
384
- });
385
- }
386
- }
387
- const avgDaysSinceEdit = editAges.length > 0 ? Math.round(editAges.reduce((a, b) => a + b, 0) / editAges.length) : null;
388
- const signals = {
389
- pagesActive: pagesCreated + pagesUpdated,
390
- pagesCreated,
391
- pagesUpdated,
392
- uniqueEditors: editors.size,
393
- stalePages,
394
- avgDaysSinceEdit,
395
- topPages: topPages.slice(0, 5).map((p) => p.title)
396
- };
397
- events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
398
- return { events, signals };
399
- }
400
- function formatNotionSignalsForPrompt(signals) {
401
- if (signals.pagesActive === 0 && signals.stalePages === 0) return "";
402
- const lines = [
403
- "## Notion Activity (documentation behavior)",
404
- "",
405
- `${signals.pagesActive} pages active in window (${signals.pagesCreated} created, ${signals.pagesUpdated} updated).`,
406
- `${signals.uniqueEditors} unique editors.`
407
- ];
408
- if (signals.stalePages > 0) {
409
- lines.push(`${signals.stalePages} pages haven't been touched in 30+ days.`);
410
- }
411
- if (signals.avgDaysSinceEdit !== null) {
412
- lines.push(`Average page age since last edit: ${signals.avgDaysSinceEdit} days.`);
413
- }
414
- if (signals.topPages.length > 0) {
415
- lines.push(`Recently active pages: ${signals.topPages.join(", ")}.`);
416
- }
417
- lines.push("");
418
- lines.push("Documentation is how the team crystallizes and shares knowledge.");
419
- lines.push("High code velocity + low documentation = building without recording.");
420
- lines.push("High documentation + low code = planning without shipping.");
421
- lines.push("Compare Notion activity against GitHub and Discord to find the balance.");
422
- return lines.join("\n");
423
- }
424
- function extractTitle(page) {
425
- for (const prop of Object.values(page.properties)) {
426
- if (prop.type === "title" && prop.title) {
427
- return prop.title.map((t) => t.plain_text).join("") || "Untitled";
428
- }
429
- }
430
- return "Untitled";
431
- }
432
- async function fetchNotionAPI(url, headers, init) {
433
- const res = await fetch(url, {
434
- method: init?.method ?? "GET",
435
- headers,
436
- body: init?.body
437
- });
438
- if (!res.ok) {
439
- throw new Error(
440
- `Notion API error ${res.status}: ${(await res.text()).slice(0, 300)}`
441
- );
442
- }
443
- return await res.json();
444
- }
445
-
446
65
  // src/radiant/index.ts
447
66
  var RADIANT_PACKAGE_VERSION = "0.0.0";
448
67
  export {
@@ -456,10 +75,15 @@ export {
456
75
  classifyActorDomain,
457
76
  classifyEvents,
458
77
  composeSystemPrompt,
78
+ compressExocortex,
79
+ compressLens,
80
+ compressPriorReads,
81
+ compressWorldmodel,
459
82
  computePersistence,
460
83
  createAnthropicAI,
461
84
  createMockAI,
462
85
  createMockGitHubAdapter,
86
+ discoverWorlds,
463
87
  emergent,
464
88
  extractSignals,
465
89
  fetchDiscordActivity,
@@ -467,6 +91,7 @@ export {
467
91
  fetchGitHubOrgActivity,
468
92
  fetchNotionActivity,
469
93
  fetchSlackActivity,
94
+ formatActiveWorlds,
470
95
  formatDiscordSignalsForPrompt,
471
96
  formatExocortexForPrompt,
472
97
  formatNotionSignalsForPrompt,
@@ -491,6 +116,7 @@ export {
491
116
  scoreCyber,
492
117
  scoreLife,
493
118
  scoreNeuroVerse,
119
+ sovereignConduitLens,
494
120
  summarizeExocortex,
495
121
  think,
496
122
  updateKnowledge,
@@ -3,8 +3,8 @@ import {
3
3
  emergent,
4
4
  parseRepoScope,
5
5
  think
6
- } from "./chunk-MC6O5GV5.js";
7
- import "./chunk-VGFDMPVB.js";
6
+ } from "./chunk-ETDIEVAX.js";
7
+ import "./chunk-F2LWMOM5.js";
8
8
  import "./chunk-I4RTIMLX.js";
9
9
  import "./chunk-ZAF6JH23.js";
10
10
  import "./chunk-QLPTHTVB.js";
@@ -0,0 +1,195 @@
1
+ import "./chunk-QWGCMQQD.js";
2
+
3
+ // src/cli/worldmodel-create.ts
4
+ import { createInterface } from "readline";
5
+ import { writeFileSync } from "fs";
6
+ import { resolve } from "path";
7
+ var QUESTIONS = [
8
+ {
9
+ id: "name",
10
+ question: "What should we call this model? (Your name, your org, your project)",
11
+ placeholder: 'e.g., "Kirsten", "Auki", "My Startup"'
12
+ },
13
+ {
14
+ id: "mission",
15
+ question: "In one or two sentences \u2014 what does this system exist to do? Not a slogan. The real purpose.",
16
+ placeholder: 'e.g., "Protect human thinking while expanding cognitive capability through AI"'
17
+ },
18
+ {
19
+ id: "domains",
20
+ question: "What are the 2-3 big areas of focus? Not departments \u2014 the major kinds of work that matter most. Separate with commas.",
21
+ placeholder: 'e.g., "Safety and boundaries, Individual authority, AI as cognitive extension"'
22
+ },
23
+ {
24
+ id: "overlaps",
25
+ question: "When those areas work well TOGETHER, what does that feel like? Name a feeling for each pair.",
26
+ placeholder: 'e.g., "Safety + Authority = Trust, Authority + AI = Possibility"'
27
+ },
28
+ {
29
+ id: "center",
30
+ question: "When EVERYTHING is aligned \u2014 all areas working together \u2014 what does the system become? One name or phrase.",
31
+ placeholder: 'e.g., "The Sovereign Conduit", "Collective Vanguard Leader"'
32
+ },
33
+ {
34
+ id: "nonnegotiables",
35
+ question: "What's absolutely non-negotiable? What would you walk away over? List a few.",
36
+ placeholder: 'e.g., "Humans retain authority over thinking. AI extends, never replaces. People can always leave."'
37
+ },
38
+ {
39
+ id: "success",
40
+ question: `What does success look like in action? What would you point at and say "that's what I mean"?`,
41
+ placeholder: 'e.g., "Someone maintaining clear authorship of decisions even when AI contributed"'
42
+ },
43
+ {
44
+ id: "drift",
45
+ question: "What does drift look like? What would worry you if you saw it happening?",
46
+ placeholder: 'e.g., "Decision ownership quietly shifting to AI without explicit delegation"'
47
+ },
48
+ {
49
+ id: "priorities",
50
+ question: 'When tradeoffs appear, what wins? Give a few "X over Y" pairs.',
51
+ placeholder: 'e.g., "Safety over speed, sovereignty over convenience, diversity over uniformity"'
52
+ }
53
+ ];
54
+ async function askQuestions() {
55
+ const rl = createInterface({
56
+ input: process.stdin,
57
+ output: process.stderr
58
+ // questions to stderr so stdout stays clean
59
+ });
60
+ const answers = {};
61
+ process.stderr.write("\n");
62
+ process.stderr.write(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n");
63
+ process.stderr.write(" \u2551 NeuroVerseOS \u2014 Build your thinking constitution \u2551\n");
64
+ process.stderr.write(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n");
65
+ process.stderr.write("\n");
66
+ process.stderr.write(" Answer these questions in your own words.\n");
67
+ process.stderr.write(" There are no wrong answers \u2014 just say what you mean.\n");
68
+ process.stderr.write(" The AI will structure your answers into a worldmodel.\n\n");
69
+ for (const q of QUESTIONS) {
70
+ const answer = await new Promise((resolve2) => {
71
+ process.stderr.write(` \x1B[1m${q.question}\x1B[0m
72
+ `);
73
+ process.stderr.write(` \x1B[2m${q.placeholder}\x1B[0m
74
+ `);
75
+ rl.question(" > ", (ans) => {
76
+ process.stderr.write("\n");
77
+ resolve2(ans.trim());
78
+ });
79
+ });
80
+ answers[q.id] = answer;
81
+ }
82
+ rl.close();
83
+ return answers;
84
+ }
85
+ async function structureWorldmodel(answers, apiKey) {
86
+ const prompt = buildStructuringPrompt(answers);
87
+ const res = await fetch("https://api.anthropic.com/v1/messages", {
88
+ method: "POST",
89
+ headers: {
90
+ "x-api-key": apiKey,
91
+ "anthropic-version": "2023-06-01",
92
+ "content-type": "application/json"
93
+ },
94
+ body: JSON.stringify({
95
+ model: "claude-sonnet-4-20250514",
96
+ max_tokens: 4096,
97
+ system: "You are a behavioral model architect. You take conversational answers about an organization's values, purpose, and priorities, and structure them into a precise .worldmodel.md file that follows the NeuroVerseOS three-layer format. Output ONLY the markdown file content, nothing else.",
98
+ messages: [{ role: "user", content: prompt }]
99
+ })
100
+ });
101
+ if (!res.ok) {
102
+ throw new Error(`AI structuring failed: ${res.status}`);
103
+ }
104
+ const data = await res.json();
105
+ const text = data.content?.filter((c) => c.type === "text").map((c) => c.text ?? "").join("");
106
+ if (!text) throw new Error("AI returned no content");
107
+ return text.replace(/^```markdown\n?/, "").replace(/\n?```$/, "").trim();
108
+ }
109
+ function buildStructuringPrompt(answers) {
110
+ return `Structure these conversational answers into a .worldmodel.md file.
111
+
112
+ The file MUST follow this exact three-layer format:
113
+
114
+ ---
115
+ name: ${answers.name}
116
+ version: 1.0.0
117
+ ---
118
+
119
+ # Core Model Geometry
120
+
121
+ ## Mission
122
+ (from the mission answer)
123
+
124
+ ## Domains
125
+ (2-4 domains from the domains answer, each with:)
126
+ ### Domain Name
127
+ #### Skills (8-10 skills per domain, inferred from the answers)
128
+ #### Values (3-4 values per domain, drawn from the non-negotiables + mission)
129
+
130
+ ## Overlap Effects
131
+ (from the overlaps answer, formatted as: Domain A + Domain B = Emergent State)
132
+
133
+ ## Center Identity
134
+ (from the center answer)
135
+
136
+ # Contextual Modifiers
137
+
138
+ ## Authority Layers
139
+ (infer 4-5 authority levels appropriate to this organization)
140
+
141
+ ## Spatial Contexts
142
+ (infer 4-5 contexts where behavior happens)
143
+
144
+ ## Interpretation Rules
145
+ (infer 3-5 rules about how context changes meaning)
146
+
147
+ # Evolution Layer
148
+
149
+ ## Aligned Behaviors
150
+ (from the success answer, expanded to 5-8 items)
151
+
152
+ ## Drift Behaviors
153
+ (from the drift answer, expanded to 5-8 items)
154
+
155
+ ## Signals
156
+ (infer 5-7 observable signals from the answers, snake_case)
157
+
158
+ ## Decision Priorities
159
+ (from the priorities answer, formatted as: preferred > secondary)
160
+
161
+ ## Evolution Conditions
162
+ (infer 3-5 conditions for when the model should adapt)
163
+
164
+ HERE ARE THE ANSWERS:
165
+
166
+ Name: ${answers.name}
167
+
168
+ Mission: ${answers.mission}
169
+
170
+ Domains: ${answers.domains}
171
+
172
+ Overlaps: ${answers.overlaps}
173
+
174
+ Center identity: ${answers.center}
175
+
176
+ Non-negotiables: ${answers.nonnegotiables}
177
+
178
+ Success looks like: ${answers.success}
179
+
180
+ Drift looks like: ${answers.drift}
181
+
182
+ Priorities: ${answers.priorities}
183
+
184
+ Output ONLY the .worldmodel.md content. No explanation. No commentary. Just the file.`;
185
+ }
186
+ function saveWorldmodel(content, outputPath) {
187
+ const resolved = resolve(outputPath);
188
+ writeFileSync(resolved, content, "utf-8");
189
+ return resolved;
190
+ }
191
+ export {
192
+ askQuestions,
193
+ saveWorldmodel,
194
+ structureWorldmodel
195
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuroverseos/governance",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Deterministic governance engine for AI agents — enforce worlds (permanent rules) and plans (mission constraints) with full audit trace",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",