@neuroverseos/governance 0.6.0 → 0.7.0
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.
- package/README.md +0 -3
- package/dist/{build-UTVDGHB3.js → build-EGBGZFIJ.js} +2 -2
- package/dist/chunk-T6EQ7ZBG.js +1571 -0
- package/dist/chunk-VGFDMPVB.js +436 -0
- package/dist/cli/neuroverse.cjs +2931 -213
- package/dist/cli/neuroverse.js +41 -90
- package/dist/cli/radiant.cjs +3997 -0
- package/dist/cli/radiant.d.cts +25 -0
- package/dist/cli/radiant.d.ts +25 -0
- package/dist/cli/radiant.js +429 -0
- package/dist/{derive-42IJW7JI.js → derive-7Y7YWVLU.js} +2 -2
- package/dist/index.js +28 -28
- package/dist/lenses-K5FVSALR.js +13 -0
- package/dist/radiant/index.cjs +3249 -0
- package/dist/radiant/index.d.cts +1301 -0
- package/dist/radiant/index.d.ts +1301 -0
- package/dist/radiant/index.js +90 -0
- package/dist/server-BXMC5NOE.js +271 -0
- package/dist/worlds/behavioral-demo.nv-world.md +50 -3
- package/package.json +7 -2
- package/dist/{chunk-735Z3HA4.js → chunk-FHXXD2TI.js} +3 -3
- package/dist/{configure-ai-5MP5DWTT.js → configure-ai-LL3VAPQW.js} +3 -3
|
@@ -0,0 +1,1571 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getLens
|
|
3
|
+
} from "./chunk-VGFDMPVB.js";
|
|
4
|
+
import {
|
|
5
|
+
loadWorld
|
|
6
|
+
} from "./chunk-I4RTIMLX.js";
|
|
7
|
+
import {
|
|
8
|
+
evaluateGuard
|
|
9
|
+
} from "./chunk-ZAF6JH23.js";
|
|
10
|
+
|
|
11
|
+
// src/radiant/core/prompt.ts
|
|
12
|
+
function composeSystemPrompt(worldmodelContent, lens) {
|
|
13
|
+
const sections = [];
|
|
14
|
+
sections.push(
|
|
15
|
+
`## Worldmodel
|
|
16
|
+
|
|
17
|
+
You are operating inside a governed environment. The worldmodel below
|
|
18
|
+
defines the invariants, signals, decision priorities, and behavioral
|
|
19
|
+
expectations for this organization. Every response you produce must
|
|
20
|
+
be grounded in this worldmodel.
|
|
21
|
+
|
|
22
|
+
` + worldmodelContent
|
|
23
|
+
);
|
|
24
|
+
const frame = lens.primary_frame;
|
|
25
|
+
const questionsBlock = frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n");
|
|
26
|
+
const overlapsBlock = frame.overlaps.map(
|
|
27
|
+
(o) => `- ${o.domains[0]} + ${o.domains[1]} = **${o.emergent_state}**: ${o.description}`
|
|
28
|
+
).join("\n");
|
|
29
|
+
sections.push(
|
|
30
|
+
`## How to Think (Analytical Frame: ${lens.name})
|
|
31
|
+
|
|
32
|
+
${frame.scoring_rubric}
|
|
33
|
+
|
|
34
|
+
### Evaluation questions to reason through
|
|
35
|
+
|
|
36
|
+
${questionsBlock}
|
|
37
|
+
|
|
38
|
+
### Overlap emergent states
|
|
39
|
+
|
|
40
|
+
${overlapsBlock}
|
|
41
|
+
|
|
42
|
+
### Center identity
|
|
43
|
+
|
|
44
|
+
When all dimensions integrate fully: **${frame.center_identity}**. Surface this sparingly \u2014 only when the integration is genuinely complete.`
|
|
45
|
+
);
|
|
46
|
+
const vocabPreferred = Object.entries(lens.vocabulary.preferred).map(([generic, native]) => `- "${generic}" \u2192 **${native}**`).join("\n");
|
|
47
|
+
const vocabArchitecture = lens.vocabulary.architecture.map((t) => `\`${t}\``).join(", ");
|
|
48
|
+
const vocabProperNouns = lens.vocabulary.proper_nouns.map((n) => `**${n}**`).join(", ");
|
|
49
|
+
const strategicBlock = lens.strategic_patterns.map((p) => `- ${p}`).join("\n");
|
|
50
|
+
sections.push(
|
|
51
|
+
`## How to Speak (Voice: ${lens.name})
|
|
52
|
+
|
|
53
|
+
Register: ${lens.voice.register}
|
|
54
|
+
|
|
55
|
+
Rules:
|
|
56
|
+
- Active voice: ${lens.voice.active_voice}
|
|
57
|
+
- Named specificity (people, places, numbers): ${lens.voice.specificity}
|
|
58
|
+
- Hype vocabulary: ${lens.voice.hype_vocabulary}
|
|
59
|
+
- Hedging / qualified phrasing: ${lens.voice.hedging}
|
|
60
|
+
- Playfulness: ${lens.voice.playfulness}
|
|
61
|
+
- Close with strategic frame: ${lens.voice.close_with_strategic_frame}
|
|
62
|
+
- Honesty about failure: ${lens.voice.honesty_about_failure}
|
|
63
|
+
|
|
64
|
+
### Output translation discipline
|
|
65
|
+
|
|
66
|
+
${lens.voice.output_translation}
|
|
67
|
+
|
|
68
|
+
### Vocabulary
|
|
69
|
+
|
|
70
|
+
Proper nouns (use literally): ${vocabProperNouns}
|
|
71
|
+
|
|
72
|
+
Preferred term substitutions:
|
|
73
|
+
${vocabPreferred}
|
|
74
|
+
|
|
75
|
+
Architecture vocabulary: ${vocabArchitecture}
|
|
76
|
+
|
|
77
|
+
### Strategic decision patterns
|
|
78
|
+
|
|
79
|
+
When recommending action, these patterns reflect how this organization resolves tradeoffs:
|
|
80
|
+
|
|
81
|
+
${strategicBlock}`
|
|
82
|
+
);
|
|
83
|
+
const forbiddenBlock = lens.forbidden_phrases.map((p) => `- "${p}"`).join("\n");
|
|
84
|
+
sections.push(
|
|
85
|
+
`## Guardrails
|
|
86
|
+
|
|
87
|
+
Do NOT use any of these phrases in your response. If you catch yourself
|
|
88
|
+
reaching for one, rephrase in direct, active, specific language instead.
|
|
89
|
+
|
|
90
|
+
${forbiddenBlock}
|
|
91
|
+
|
|
92
|
+
If your response would violate a worldmodel invariant, state the conflict
|
|
93
|
+
explicitly and propose an alternative that honors the invariant.`
|
|
94
|
+
);
|
|
95
|
+
return sections.join("\n\n---\n\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/radiant/core/voice-check.ts
|
|
99
|
+
function checkForbiddenPhrases(lens, text) {
|
|
100
|
+
const lower = text.toLowerCase();
|
|
101
|
+
const violations = [];
|
|
102
|
+
for (const phrase of lens.forbidden_phrases) {
|
|
103
|
+
const phraseLower = phrase.toLowerCase();
|
|
104
|
+
let pos = 0;
|
|
105
|
+
while (true) {
|
|
106
|
+
const idx = lower.indexOf(phraseLower, pos);
|
|
107
|
+
if (idx === -1) break;
|
|
108
|
+
violations.push({ phrase, offset: idx });
|
|
109
|
+
pos = idx + phraseLower.length;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
violations.sort((a, b) => a.offset - b.offset);
|
|
113
|
+
return violations;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/radiant/commands/think.ts
|
|
117
|
+
async function think(input) {
|
|
118
|
+
const lens = resolveLens(input.lensId);
|
|
119
|
+
const systemPrompt = composeSystemPrompt(input.worldmodelContent, lens);
|
|
120
|
+
const response = await input.ai.complete(systemPrompt, input.query);
|
|
121
|
+
const voiceViolations = checkForbiddenPhrases(lens, response);
|
|
122
|
+
return {
|
|
123
|
+
response,
|
|
124
|
+
lens: lens.name,
|
|
125
|
+
voiceViolations,
|
|
126
|
+
voiceClean: voiceViolations.length === 0,
|
|
127
|
+
systemPrompt
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function resolveLens(id) {
|
|
131
|
+
const lens = getLens(id);
|
|
132
|
+
if (!lens) {
|
|
133
|
+
const available = Object.keys(
|
|
134
|
+
// Inline import-free way to list. At runtime, getLens returns from
|
|
135
|
+
// the same LENSES record — we just need the keys for the error message.
|
|
136
|
+
// We re-import getLens from lenses/index which exposes listLenses, but
|
|
137
|
+
// since we already have lens===undefined we know the id was wrong.
|
|
138
|
+
{}
|
|
139
|
+
);
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Lens "${id}" not found. Check the id or register the lens in src/radiant/lenses/index.ts.`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return lens;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/radiant/core/scopes.ts
|
|
148
|
+
function parseRepoScope(scope) {
|
|
149
|
+
const cleaned = scope.replace(/^https?:\/\//, "").replace(/^github\.com\//, "").replace(/\.git$/, "").replace(/\/$/, "");
|
|
150
|
+
const parts = cleaned.split("/");
|
|
151
|
+
if (parts.length < 2 || !parts[0] || !parts[1]) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Cannot parse repo scope: "${scope}". Expected "owner/repo" or a GitHub URL.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return { owner: parts[0], repo: parts[1] };
|
|
157
|
+
}
|
|
158
|
+
function formatScope(scope) {
|
|
159
|
+
return `${scope.owner}/${scope.repo}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/radiant/adapters/github.ts
|
|
163
|
+
async function fetchGitHubActivity(scope, token, options = {}) {
|
|
164
|
+
const windowDays = options.windowDays ?? 14;
|
|
165
|
+
const perPage = options.perPage ?? 100;
|
|
166
|
+
const since = new Date(
|
|
167
|
+
Date.now() - windowDays * 24 * 60 * 60 * 1e3
|
|
168
|
+
).toISOString();
|
|
169
|
+
const base = `https://api.github.com/repos/${formatScope(scope)}`;
|
|
170
|
+
const headers = {
|
|
171
|
+
Authorization: `token ${token}`,
|
|
172
|
+
Accept: "application/vnd.github.v3+json",
|
|
173
|
+
"User-Agent": "neuroverseos-radiant"
|
|
174
|
+
};
|
|
175
|
+
const events = [];
|
|
176
|
+
const [commits, prs, comments] = await Promise.all([
|
|
177
|
+
fetchJSON(
|
|
178
|
+
`${base}/commits?since=${since}&per_page=${perPage}`,
|
|
179
|
+
headers
|
|
180
|
+
),
|
|
181
|
+
fetchJSON(
|
|
182
|
+
`${base}/pulls?state=all&sort=updated&direction=desc&per_page=${perPage}`,
|
|
183
|
+
headers
|
|
184
|
+
),
|
|
185
|
+
fetchJSON(
|
|
186
|
+
`${base}/issues/comments?since=${since}&per_page=${perPage}&sort=updated&direction=desc`,
|
|
187
|
+
headers
|
|
188
|
+
)
|
|
189
|
+
]);
|
|
190
|
+
for (const c of commits) {
|
|
191
|
+
events.push(mapCommit(c, scope));
|
|
192
|
+
}
|
|
193
|
+
const sinceDate = new Date(since);
|
|
194
|
+
for (const pr of prs) {
|
|
195
|
+
if (new Date(pr.updated_at) >= sinceDate) {
|
|
196
|
+
events.push(mapPR(pr, scope));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const comment of comments) {
|
|
200
|
+
events.push(mapComment(comment, scope));
|
|
201
|
+
}
|
|
202
|
+
events.sort(
|
|
203
|
+
(a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)
|
|
204
|
+
);
|
|
205
|
+
return events;
|
|
206
|
+
}
|
|
207
|
+
function mapCommit(c, scope) {
|
|
208
|
+
const actor = mapUser(c.author, c.commit.author.name);
|
|
209
|
+
const coActors = extractCoAuthors(c.commit.message);
|
|
210
|
+
return {
|
|
211
|
+
id: `commit-${c.sha.slice(0, 8)}`,
|
|
212
|
+
timestamp: c.commit.author.date,
|
|
213
|
+
actor,
|
|
214
|
+
coActors: coActors.length > 0 ? coActors : void 0,
|
|
215
|
+
kind: "commit",
|
|
216
|
+
content: c.commit.message,
|
|
217
|
+
metadata: {
|
|
218
|
+
scope: formatScope(scope),
|
|
219
|
+
sha: c.sha
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function mapPR(pr, scope) {
|
|
224
|
+
const event = {
|
|
225
|
+
id: `pr-${pr.number}`,
|
|
226
|
+
timestamp: pr.created_at,
|
|
227
|
+
actor: mapUser(pr.user),
|
|
228
|
+
kind: pr.merged_at ? "pr_merged" : pr.state === "open" ? "pr_opened" : "pr_closed",
|
|
229
|
+
content: `${pr.title}
|
|
230
|
+
|
|
231
|
+
${pr.body ?? ""}`.trim(),
|
|
232
|
+
metadata: {
|
|
233
|
+
scope: formatScope(scope),
|
|
234
|
+
pr_number: pr.number,
|
|
235
|
+
state: pr.state,
|
|
236
|
+
merged_at: pr.merged_at
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
if (pr.merged_by && pr.merged_by.login !== pr.user.login) {
|
|
240
|
+
event.actor = mapUser(pr.merged_by);
|
|
241
|
+
event.kind = "pr_merged";
|
|
242
|
+
event.timestamp = pr.merged_at ?? pr.updated_at;
|
|
243
|
+
event.respondsTo = {
|
|
244
|
+
eventId: `pr-${pr.number}-opened`,
|
|
245
|
+
actor: mapUser(pr.user)
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return event;
|
|
249
|
+
}
|
|
250
|
+
function mapComment(comment, scope) {
|
|
251
|
+
const issueMatch = comment.issue_url.match(/\/issues\/(\d+)$/);
|
|
252
|
+
const issueNumber = issueMatch ? issueMatch[1] : "unknown";
|
|
253
|
+
const event = {
|
|
254
|
+
id: `comment-${comment.id}`,
|
|
255
|
+
timestamp: comment.created_at,
|
|
256
|
+
actor: mapUser(comment.user),
|
|
257
|
+
kind: "comment",
|
|
258
|
+
content: comment.body,
|
|
259
|
+
respondsTo: {
|
|
260
|
+
eventId: `pr-${issueNumber}`,
|
|
261
|
+
actor: { id: "unknown", kind: "unknown" }
|
|
262
|
+
},
|
|
263
|
+
metadata: {
|
|
264
|
+
scope: formatScope(scope),
|
|
265
|
+
issue_number: issueNumber
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
return event;
|
|
269
|
+
}
|
|
270
|
+
var KNOWN_AI_LOGINS = /* @__PURE__ */ new Set([
|
|
271
|
+
"github-actions[bot]",
|
|
272
|
+
"dependabot[bot]",
|
|
273
|
+
"renovate[bot]",
|
|
274
|
+
"copilot"
|
|
275
|
+
]);
|
|
276
|
+
var KNOWN_AI_CO_AUTHOR_NAMES = /* @__PURE__ */ new Set([
|
|
277
|
+
"claude",
|
|
278
|
+
"copilot",
|
|
279
|
+
"cursor",
|
|
280
|
+
"codeium",
|
|
281
|
+
"tabnine",
|
|
282
|
+
"codex"
|
|
283
|
+
]);
|
|
284
|
+
function mapUser(ghUser, fallbackName) {
|
|
285
|
+
if (!ghUser) {
|
|
286
|
+
return {
|
|
287
|
+
id: fallbackName ?? "unknown",
|
|
288
|
+
kind: "unknown",
|
|
289
|
+
name: fallbackName
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
let kind = "human";
|
|
293
|
+
if (ghUser.type === "Bot" || ghUser.login.endsWith("[bot]")) {
|
|
294
|
+
kind = "bot";
|
|
295
|
+
}
|
|
296
|
+
if (KNOWN_AI_LOGINS.has(ghUser.login.toLowerCase())) {
|
|
297
|
+
kind = "bot";
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
id: ghUser.login,
|
|
301
|
+
kind,
|
|
302
|
+
name: ghUser.login
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function extractCoAuthors(message) {
|
|
306
|
+
const coAuthors = [];
|
|
307
|
+
const lines = message.split("\n");
|
|
308
|
+
for (const line of lines) {
|
|
309
|
+
const match = line.match(
|
|
310
|
+
/^Co-authored-by:\s*(.+?)\s*<([^>]*)>/i
|
|
311
|
+
);
|
|
312
|
+
if (match) {
|
|
313
|
+
const name = match[1].trim().toLowerCase();
|
|
314
|
+
const isAI = KNOWN_AI_CO_AUTHOR_NAMES.has(name) || [...KNOWN_AI_CO_AUTHOR_NAMES].some((ai) => name.includes(ai));
|
|
315
|
+
coAuthors.push({
|
|
316
|
+
id: match[2] || name,
|
|
317
|
+
kind: isAI ? "ai" : "human",
|
|
318
|
+
name: match[1].trim()
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return coAuthors;
|
|
323
|
+
}
|
|
324
|
+
async function fetchJSON(url, headers) {
|
|
325
|
+
const res = await fetch(url, { headers });
|
|
326
|
+
if (!res.ok) {
|
|
327
|
+
if (res.status === 404) return [];
|
|
328
|
+
if (res.status === 403) {
|
|
329
|
+
const body = await res.text();
|
|
330
|
+
if (body.includes("rate limit")) {
|
|
331
|
+
throw new Error(
|
|
332
|
+
`GitHub API rate limit exceeded. Wait or use a token with higher limits.`
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
throw new Error(
|
|
337
|
+
`GitHub API error ${res.status} for ${url}: ${(await res.text()).slice(0, 300)}`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
return await res.json();
|
|
341
|
+
}
|
|
342
|
+
function createMockGitHubAdapter(fixedEvents) {
|
|
343
|
+
return async () => fixedEvents;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/radiant/adapters/exocortex.ts
|
|
347
|
+
import { readFileSync, existsSync } from "fs";
|
|
348
|
+
import { join, resolve } from "path";
|
|
349
|
+
function readExocortex(dirPath) {
|
|
350
|
+
const dir = resolve(dirPath);
|
|
351
|
+
let filesLoaded = 0;
|
|
352
|
+
function tryRead(...paths) {
|
|
353
|
+
for (const p of paths) {
|
|
354
|
+
const full = join(dir, p);
|
|
355
|
+
if (existsSync(full)) {
|
|
356
|
+
try {
|
|
357
|
+
const content = readFileSync(full, "utf-8").trim();
|
|
358
|
+
if (content) {
|
|
359
|
+
filesLoaded++;
|
|
360
|
+
return content;
|
|
361
|
+
}
|
|
362
|
+
} catch {
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
const ctx = {
|
|
369
|
+
attention: tryRead("attention.md"),
|
|
370
|
+
goals: tryRead("goals.md"),
|
|
371
|
+
identity: tryRead("identity.md"),
|
|
372
|
+
sprint: tryRead("sprint.md", "src/sprint.md"),
|
|
373
|
+
organization: tryRead("org/organization.md", "org/src/organization.md"),
|
|
374
|
+
methods: tryRead("org/methods.md", "org/src/methods.md"),
|
|
375
|
+
source: dir,
|
|
376
|
+
filesLoaded
|
|
377
|
+
};
|
|
378
|
+
return ctx;
|
|
379
|
+
}
|
|
380
|
+
function formatExocortexForPrompt(ctx) {
|
|
381
|
+
if (ctx.filesLoaded === 0) return "";
|
|
382
|
+
const sections = [];
|
|
383
|
+
sections.push(
|
|
384
|
+
"## Stated Intent (from exocortex)\n\nThe following is what the person/team SAYS they are doing, focused on, and working toward. Compare this against the ACTUAL activity from GitHub. Where stated intent and observed behavior diverge, that gap is the most valuable signal in this read. Name it directly."
|
|
385
|
+
);
|
|
386
|
+
if (ctx.attention) {
|
|
387
|
+
sections.push(`### Current attention
|
|
388
|
+
|
|
389
|
+
${ctx.attention}`);
|
|
390
|
+
}
|
|
391
|
+
if (ctx.goals) {
|
|
392
|
+
sections.push(`### Goals
|
|
393
|
+
|
|
394
|
+
${ctx.goals}`);
|
|
395
|
+
}
|
|
396
|
+
if (ctx.sprint) {
|
|
397
|
+
sections.push(`### Sprint focus
|
|
398
|
+
|
|
399
|
+
${ctx.sprint}`);
|
|
400
|
+
}
|
|
401
|
+
if (ctx.identity) {
|
|
402
|
+
sections.push(`### Identity and values
|
|
403
|
+
|
|
404
|
+
${ctx.identity}`);
|
|
405
|
+
}
|
|
406
|
+
if (ctx.organization) {
|
|
407
|
+
sections.push(`### Organization
|
|
408
|
+
|
|
409
|
+
${ctx.organization}`);
|
|
410
|
+
}
|
|
411
|
+
if (ctx.methods) {
|
|
412
|
+
sections.push(`### Methods
|
|
413
|
+
|
|
414
|
+
${ctx.methods}`);
|
|
415
|
+
}
|
|
416
|
+
return sections.join("\n\n");
|
|
417
|
+
}
|
|
418
|
+
function summarizeExocortex(ctx) {
|
|
419
|
+
if (ctx.filesLoaded === 0) return "no exocortex files found";
|
|
420
|
+
const loaded = [];
|
|
421
|
+
if (ctx.attention) loaded.push("attention");
|
|
422
|
+
if (ctx.goals) loaded.push("goals");
|
|
423
|
+
if (ctx.sprint) loaded.push("sprint");
|
|
424
|
+
if (ctx.identity) loaded.push("identity");
|
|
425
|
+
if (ctx.organization) loaded.push("org");
|
|
426
|
+
if (ctx.methods) loaded.push("methods");
|
|
427
|
+
return `${loaded.join(", ")} (${ctx.filesLoaded} files)`;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/radiant/memory/palace.ts
|
|
431
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, readdirSync, existsSync as existsSync2 } from "fs";
|
|
432
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
433
|
+
function writeRead(exocortexDir, frontmatter, text) {
|
|
434
|
+
const dir = resolve2(exocortexDir, "radiant", "reads");
|
|
435
|
+
mkdirSync(dir, { recursive: true });
|
|
436
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
437
|
+
const filename = `${date}.md`;
|
|
438
|
+
const filepath = join2(dir, filename);
|
|
439
|
+
const content = `${frontmatter}
|
|
440
|
+
|
|
441
|
+
${text}
|
|
442
|
+
`;
|
|
443
|
+
writeFileSync(filepath, content, "utf-8");
|
|
444
|
+
return filepath;
|
|
445
|
+
}
|
|
446
|
+
function updateKnowledge(exocortexDir, persistence, options) {
|
|
447
|
+
const dir = resolve2(exocortexDir, "radiant");
|
|
448
|
+
mkdirSync(dir, { recursive: true });
|
|
449
|
+
const filepath = join2(dir, "knowledge.md");
|
|
450
|
+
const totalReads = options?.totalReads ?? 0;
|
|
451
|
+
const existingUntriggered = loadUntriggeredCounts(filepath);
|
|
452
|
+
const lines = [
|
|
453
|
+
"# Radiant \u2014 Accumulated Behavioral Knowledge",
|
|
454
|
+
"",
|
|
455
|
+
`Last updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
|
|
456
|
+
`Total reads: ${totalReads}`,
|
|
457
|
+
"",
|
|
458
|
+
"---",
|
|
459
|
+
"",
|
|
460
|
+
"## Evolution proposals",
|
|
461
|
+
""
|
|
462
|
+
];
|
|
463
|
+
const addCandidates = persistence.filter((p) => p.occurrences >= 3);
|
|
464
|
+
if (addCandidates.length > 0) {
|
|
465
|
+
lines.push("### Consider adding");
|
|
466
|
+
lines.push("");
|
|
467
|
+
lines.push("These candidate patterns keep recurring. They are not yet in the worldmodel.");
|
|
468
|
+
lines.push("If they represent real behavioral patterns worth tracking, add them.");
|
|
469
|
+
lines.push("If they were temporary, dismiss them.");
|
|
470
|
+
lines.push("");
|
|
471
|
+
for (const p of addCandidates) {
|
|
472
|
+
lines.push(
|
|
473
|
+
`- **${p.name}** \u2014 observed ${p.occurrences} times (${p.dates.join(", ")}). Add to auki-strategy.worldmodel.md \u2192 Evolution Layer \u2192 Drift Behaviors (if concerning) or Aligned Behaviors (if healthy).`
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
lines.push("");
|
|
477
|
+
}
|
|
478
|
+
if (options?.declaredItems && options.declaredItems.length > 0) {
|
|
479
|
+
const triggered = new Set(options.triggeredItems ?? []);
|
|
480
|
+
const removeCandidates = [];
|
|
481
|
+
for (const item of options.declaredItems) {
|
|
482
|
+
if (!triggered.has(item.name)) {
|
|
483
|
+
const prior = existingUntriggered.get(item.name) ?? 0;
|
|
484
|
+
const count = prior + 1;
|
|
485
|
+
existingUntriggered.set(item.name, count);
|
|
486
|
+
if (count >= 4) {
|
|
487
|
+
removeCandidates.push({ item, weeksSilent: count });
|
|
488
|
+
}
|
|
489
|
+
} else {
|
|
490
|
+
existingUntriggered.set(item.name, 0);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (removeCandidates.length > 0) {
|
|
494
|
+
lines.push("### Consider removing");
|
|
495
|
+
lines.push("");
|
|
496
|
+
lines.push("These items are declared in the worldmodel but haven't triggered in multiple reads.");
|
|
497
|
+
lines.push("Either the team has internalized them (the rule is redundant) or they haven't been tested.");
|
|
498
|
+
lines.push("A lean worldmodel with 5 sharp invariants is stronger than a bloated one with 20.");
|
|
499
|
+
lines.push("");
|
|
500
|
+
for (const { item, weeksSilent } of removeCandidates) {
|
|
501
|
+
lines.push(
|
|
502
|
+
`- **${item.name}** (${item.type}) \u2014 hasn't triggered in ${weeksSilent} reads. Internalized or untested? Review whether it still earns its place.`
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
lines.push("");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (options?.triggeredItems && options.triggeredItems.length > 0) {
|
|
509
|
+
lines.push("### Keep (recently active)");
|
|
510
|
+
lines.push("");
|
|
511
|
+
lines.push("These worldmodel items triggered governance in the most recent read. They're earning their place.");
|
|
512
|
+
lines.push("");
|
|
513
|
+
for (const name of options.triggeredItems) {
|
|
514
|
+
lines.push(`- **${name}** \u2014 triggered this read. Holding.`);
|
|
515
|
+
}
|
|
516
|
+
lines.push("");
|
|
517
|
+
}
|
|
518
|
+
lines.push("---");
|
|
519
|
+
lines.push("");
|
|
520
|
+
lines.push("## Pattern persistence (all observed)");
|
|
521
|
+
lines.push("");
|
|
522
|
+
for (const p of persistence) {
|
|
523
|
+
const status = p.occurrences >= 4 ? "**persistent**" : p.occurrences >= 2 ? "recurring" : "observed once";
|
|
524
|
+
lines.push(`### ${p.name}`);
|
|
525
|
+
lines.push(`- Status: ${status}`);
|
|
526
|
+
lines.push(`- Observed ${p.occurrences} time${p.occurrences > 1 ? "s" : ""}: ${p.dates.join(", ")}`);
|
|
527
|
+
lines.push("");
|
|
528
|
+
}
|
|
529
|
+
lines.push("---");
|
|
530
|
+
lines.push("");
|
|
531
|
+
lines.push("<!-- untriggered_counts (machine-readable, do not edit)");
|
|
532
|
+
for (const [name, count] of existingUntriggered.entries()) {
|
|
533
|
+
lines.push(`${name}=${count}`);
|
|
534
|
+
}
|
|
535
|
+
lines.push("-->");
|
|
536
|
+
writeFileSync(filepath, lines.join("\n"), "utf-8");
|
|
537
|
+
return filepath;
|
|
538
|
+
}
|
|
539
|
+
function loadUntriggeredCounts(filepath) {
|
|
540
|
+
const counts = /* @__PURE__ */ new Map();
|
|
541
|
+
if (!existsSync2(filepath)) return counts;
|
|
542
|
+
try {
|
|
543
|
+
const content = readFileSync2(filepath, "utf-8");
|
|
544
|
+
const match = content.match(
|
|
545
|
+
/<!-- untriggered_counts[\s\S]*?-->/
|
|
546
|
+
);
|
|
547
|
+
if (match) {
|
|
548
|
+
const lines = match[0].split("\n");
|
|
549
|
+
for (const line of lines) {
|
|
550
|
+
const eq = line.match(/^([^=]+)=(\d+)$/);
|
|
551
|
+
if (eq) {
|
|
552
|
+
counts.set(eq[1], parseInt(eq[2], 10));
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
} catch {
|
|
557
|
+
}
|
|
558
|
+
return counts;
|
|
559
|
+
}
|
|
560
|
+
function loadPriorReads(exocortexDir) {
|
|
561
|
+
const dir = resolve2(exocortexDir, "radiant", "reads");
|
|
562
|
+
if (!existsSync2(dir)) return [];
|
|
563
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
564
|
+
const reads = [];
|
|
565
|
+
for (const filename of files) {
|
|
566
|
+
const filepath = join2(dir, filename);
|
|
567
|
+
const content = readFileSync2(filepath, "utf-8");
|
|
568
|
+
const date = filename.replace(".md", "");
|
|
569
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
570
|
+
const frontmatter = fmMatch ? fmMatch[1] : "";
|
|
571
|
+
const patternNames = [];
|
|
572
|
+
const nameMatches = frontmatter.matchAll(/- name: ["']?([^"'\n]+)["']?/g);
|
|
573
|
+
for (const m of nameMatches) {
|
|
574
|
+
patternNames.push(m[1].trim());
|
|
575
|
+
}
|
|
576
|
+
reads.push({ date, filename, patternNames, frontmatter });
|
|
577
|
+
}
|
|
578
|
+
return reads;
|
|
579
|
+
}
|
|
580
|
+
function computePersistence(priorReads, currentPatternNames) {
|
|
581
|
+
const allPatterns = /* @__PURE__ */ new Map();
|
|
582
|
+
for (const read of priorReads) {
|
|
583
|
+
for (const name of read.patternNames) {
|
|
584
|
+
const dates = allPatterns.get(name) ?? [];
|
|
585
|
+
if (!dates.includes(read.date)) dates.push(read.date);
|
|
586
|
+
allPatterns.set(name, dates);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
590
|
+
for (const name of currentPatternNames) {
|
|
591
|
+
const dates = allPatterns.get(name) ?? [];
|
|
592
|
+
if (!dates.includes(today)) dates.push(today);
|
|
593
|
+
allPatterns.set(name, dates);
|
|
594
|
+
}
|
|
595
|
+
return Array.from(allPatterns.entries()).map(([name, dates]) => ({
|
|
596
|
+
name,
|
|
597
|
+
occurrences: dates.length,
|
|
598
|
+
dates: dates.sort()
|
|
599
|
+
})).sort((a, b) => b.occurrences - a.occurrences);
|
|
600
|
+
}
|
|
601
|
+
function formatPriorReadsForPrompt(priorReads) {
|
|
602
|
+
if (priorReads.length === 0) return "";
|
|
603
|
+
const lines = [
|
|
604
|
+
"## Prior Radiant reads (history)",
|
|
605
|
+
"",
|
|
606
|
+
`Radiant has run ${priorReads.length} time${priorReads.length > 1 ? "s" : ""} before on this scope.`,
|
|
607
|
+
"If you see patterns that appeared in prior reads, note their persistence.",
|
|
608
|
+
"Patterns that recur across 3+ reads are strong candidates for declaration in the strategy file.",
|
|
609
|
+
""
|
|
610
|
+
];
|
|
611
|
+
for (const read of priorReads.slice(-4)) {
|
|
612
|
+
lines.push(`### Read from ${read.date}`);
|
|
613
|
+
if (read.patternNames.length > 0) {
|
|
614
|
+
lines.push(`Patterns observed: ${read.patternNames.join(", ")}`);
|
|
615
|
+
} else {
|
|
616
|
+
lines.push("No patterns extracted from frontmatter.");
|
|
617
|
+
}
|
|
618
|
+
lines.push("");
|
|
619
|
+
}
|
|
620
|
+
return lines.join("\n");
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// src/radiant/core/governance.ts
|
|
624
|
+
async function auditGovernance(events, worldPath) {
|
|
625
|
+
let world;
|
|
626
|
+
try {
|
|
627
|
+
world = await loadWorld(worldPath);
|
|
628
|
+
} catch {
|
|
629
|
+
return emptyAudit(events.length, "Could not load compiled worldmodel for governance audit.");
|
|
630
|
+
}
|
|
631
|
+
const verdicts = [];
|
|
632
|
+
for (const ce of events) {
|
|
633
|
+
const intent = ce.event.content?.slice(0, 500) || ce.event.kind || "activity";
|
|
634
|
+
const scope = ce.event.metadata?.scope || void 0;
|
|
635
|
+
try {
|
|
636
|
+
const result = evaluateGuard(
|
|
637
|
+
{
|
|
638
|
+
intent,
|
|
639
|
+
scope,
|
|
640
|
+
actionCategory: mapKindToCategory(ce.event.kind)
|
|
641
|
+
},
|
|
642
|
+
world
|
|
643
|
+
);
|
|
644
|
+
verdicts.push({
|
|
645
|
+
eventId: ce.event.id,
|
|
646
|
+
domain: ce.domain,
|
|
647
|
+
status: result.status,
|
|
648
|
+
reason: result.reason,
|
|
649
|
+
ruleId: result.ruleId,
|
|
650
|
+
warning: result.warning
|
|
651
|
+
});
|
|
652
|
+
} catch {
|
|
653
|
+
verdicts.push({
|
|
654
|
+
eventId: ce.event.id,
|
|
655
|
+
domain: ce.domain,
|
|
656
|
+
status: "ALLOW",
|
|
657
|
+
reason: "guard evaluation skipped (error)"
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
const human = bucketVerdicts(verdicts.filter((v) => v.domain === "life"));
|
|
662
|
+
const cyber = bucketVerdicts(verdicts.filter((v) => v.domain === "cyber"));
|
|
663
|
+
const joint = bucketVerdicts(verdicts.filter((v) => v.domain === "joint"));
|
|
664
|
+
const summary = buildSummary(human, cyber, joint, events.length);
|
|
665
|
+
return {
|
|
666
|
+
totalEvents: events.length,
|
|
667
|
+
human,
|
|
668
|
+
cyber,
|
|
669
|
+
joint,
|
|
670
|
+
summary
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
function bucketVerdicts(verdicts) {
|
|
674
|
+
const nonAllow = verdicts.filter((v) => v.status !== "ALLOW");
|
|
675
|
+
return {
|
|
676
|
+
allow: verdicts.filter((v) => v.status === "ALLOW").length,
|
|
677
|
+
modify: verdicts.filter((v) => v.status === "MODIFY").length,
|
|
678
|
+
block: verdicts.filter((v) => v.status === "BLOCK").length,
|
|
679
|
+
details: nonAllow
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function buildSummary(human, cyber, joint, total) {
|
|
683
|
+
const humanTriggered = human.modify + human.block;
|
|
684
|
+
const cyberTriggered = cyber.modify + cyber.block;
|
|
685
|
+
const jointTriggered = joint.modify + joint.block;
|
|
686
|
+
const totalTriggered = humanTriggered + cyberTriggered + jointTriggered;
|
|
687
|
+
if (totalTriggered === 0) {
|
|
688
|
+
return `${total} events evaluated. All passed. The cocoon held \u2014 no governance triggered.`;
|
|
689
|
+
}
|
|
690
|
+
const parts = [];
|
|
691
|
+
parts.push(`${total} events evaluated. ${totalTriggered} triggered governance.`);
|
|
692
|
+
if (humanTriggered > 0) {
|
|
693
|
+
parts.push(`Human side: ${humanTriggered} (${human.block} blocked, ${human.modify} modified).`);
|
|
694
|
+
}
|
|
695
|
+
if (cyberTriggered > 0) {
|
|
696
|
+
parts.push(`AI side: ${cyberTriggered} (${cyber.block} blocked, ${cyber.modify} modified).`);
|
|
697
|
+
}
|
|
698
|
+
if (jointTriggered > 0) {
|
|
699
|
+
parts.push(`Joint work: ${jointTriggered} (${joint.block} blocked, ${joint.modify} modified).`);
|
|
700
|
+
}
|
|
701
|
+
if (humanTriggered > 0 && cyberTriggered > 0) {
|
|
702
|
+
const ratio = humanTriggered / cyberTriggered;
|
|
703
|
+
if (ratio > 2) {
|
|
704
|
+
parts.push("Human side is testing the frame more than AI. Either the worldmodel needs calibrating for human workflows, or humans are genuinely drifting.");
|
|
705
|
+
} else if (ratio < 0.5) {
|
|
706
|
+
parts.push("AI side is testing the frame more than humans. Check whether the AI's output patterns match the declared invariants.");
|
|
707
|
+
} else {
|
|
708
|
+
parts.push("Roughly balanced between human and AI \u2014 both sides are testing the frame.");
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return parts.join(" ");
|
|
712
|
+
}
|
|
713
|
+
function mapKindToCategory(kind) {
|
|
714
|
+
if (!kind) return "other";
|
|
715
|
+
if (kind.includes("commit") || kind.includes("merge")) return "write";
|
|
716
|
+
if (kind.includes("review") || kind.includes("comment")) return "read";
|
|
717
|
+
return "other";
|
|
718
|
+
}
|
|
719
|
+
function emptyAudit(total, reason) {
|
|
720
|
+
return {
|
|
721
|
+
totalEvents: total,
|
|
722
|
+
human: { allow: 0, modify: 0, block: 0, details: [] },
|
|
723
|
+
cyber: { allow: 0, modify: 0, block: 0, details: [] },
|
|
724
|
+
joint: { allow: 0, modify: 0, block: 0, details: [] },
|
|
725
|
+
summary: reason
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/radiant/core/domain.ts
|
|
730
|
+
function isLifeSide(k) {
|
|
731
|
+
return k === "human" || k === "unknown";
|
|
732
|
+
}
|
|
733
|
+
function isCyberSide(k) {
|
|
734
|
+
return k === "ai" || k === "bot";
|
|
735
|
+
}
|
|
736
|
+
function crossesBoundary(a, b) {
|
|
737
|
+
return isLifeSide(a) && isCyberSide(b) || isCyberSide(a) && isLifeSide(b);
|
|
738
|
+
}
|
|
739
|
+
function classifyActorDomain(event) {
|
|
740
|
+
const primaryKind = event.actor.kind;
|
|
741
|
+
const coKinds = (event.coActors ?? []).map((a) => a.kind);
|
|
742
|
+
const allKinds = [primaryKind, ...coKinds];
|
|
743
|
+
const hasLife = allKinds.some(isLifeSide);
|
|
744
|
+
const hasCyber = allKinds.some(isCyberSide);
|
|
745
|
+
if (hasLife && hasCyber) {
|
|
746
|
+
return "joint";
|
|
747
|
+
}
|
|
748
|
+
if (event.respondsTo && crossesBoundary(primaryKind, event.respondsTo.actor.kind)) {
|
|
749
|
+
return "joint";
|
|
750
|
+
}
|
|
751
|
+
return isCyberSide(primaryKind) ? "cyber" : "life";
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// src/radiant/core/signals.ts
|
|
755
|
+
function classifyEvents(events) {
|
|
756
|
+
return events.map((event) => ({
|
|
757
|
+
event,
|
|
758
|
+
domain: classifyActorDomain(event)
|
|
759
|
+
}));
|
|
760
|
+
}
|
|
761
|
+
function extractSignals(events, extractors = DEFAULT_SIGNAL_EXTRACTORS) {
|
|
762
|
+
const domains = ["life", "cyber", "joint"];
|
|
763
|
+
const out = [];
|
|
764
|
+
for (const extractor of extractors) {
|
|
765
|
+
for (const domain of domains) {
|
|
766
|
+
const r = extractor.extract(events, domain);
|
|
767
|
+
out.push({
|
|
768
|
+
id: extractor.id,
|
|
769
|
+
domain,
|
|
770
|
+
score: r.score,
|
|
771
|
+
eventCount: r.eventCount,
|
|
772
|
+
confidence: r.confidence
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return out;
|
|
777
|
+
}
|
|
778
|
+
var ZERO = { score: 0, eventCount: 0, confidence: 0 };
|
|
779
|
+
function inDomain(events, domain) {
|
|
780
|
+
return events.filter((e) => e.domain === domain);
|
|
781
|
+
}
|
|
782
|
+
function confidenceFromCount(count) {
|
|
783
|
+
return Math.min(1, count / 10);
|
|
784
|
+
}
|
|
785
|
+
function clamp100(n) {
|
|
786
|
+
if (n < 0) return 0;
|
|
787
|
+
if (n > 100) return 100;
|
|
788
|
+
return n;
|
|
789
|
+
}
|
|
790
|
+
var CLARITY_EXTRACTOR = {
|
|
791
|
+
id: "clarity",
|
|
792
|
+
description: "Informativeness of event content \u2014 commit messages, PR bodies, review text",
|
|
793
|
+
extract(events, domain) {
|
|
794
|
+
const sub = inDomain(events, domain);
|
|
795
|
+
if (sub.length === 0) return ZERO;
|
|
796
|
+
const totalScore = sub.reduce((acc, e) => {
|
|
797
|
+
const len = (e.event.content ?? "").length;
|
|
798
|
+
const norm = Math.min(len, 200) / 200;
|
|
799
|
+
return acc + norm * 100;
|
|
800
|
+
}, 0);
|
|
801
|
+
return {
|
|
802
|
+
score: clamp100(totalScore / sub.length),
|
|
803
|
+
eventCount: sub.length,
|
|
804
|
+
confidence: confidenceFromCount(sub.length)
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
var OWNERSHIP_EXTRACTOR = {
|
|
809
|
+
id: "ownership",
|
|
810
|
+
description: "Clarity of accountability \u2014 fraction of events with a known primary actor",
|
|
811
|
+
extract(events, domain) {
|
|
812
|
+
const sub = inDomain(events, domain);
|
|
813
|
+
if (sub.length === 0) return ZERO;
|
|
814
|
+
const attributed = sub.filter((e) => e.event.actor.kind !== "unknown").length;
|
|
815
|
+
return {
|
|
816
|
+
score: clamp100(attributed / sub.length * 100),
|
|
817
|
+
eventCount: sub.length,
|
|
818
|
+
confidence: confidenceFromCount(sub.length)
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
var FOLLOW_THROUGH_EXTRACTOR = {
|
|
823
|
+
id: "follow_through",
|
|
824
|
+
description: "Fraction of events that were followed up \u2014 i.e. referenced by a later event",
|
|
825
|
+
extract(events, domain) {
|
|
826
|
+
const sub = inDomain(events, domain);
|
|
827
|
+
if (sub.length === 0) return ZERO;
|
|
828
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
829
|
+
for (const e of events) {
|
|
830
|
+
const ref = e.event.respondsTo?.eventId;
|
|
831
|
+
if (ref) referencedIds.add(ref);
|
|
832
|
+
}
|
|
833
|
+
const followedUp = sub.filter((e) => referencedIds.has(e.event.id)).length;
|
|
834
|
+
return {
|
|
835
|
+
score: clamp100(followedUp / sub.length * 100),
|
|
836
|
+
eventCount: sub.length,
|
|
837
|
+
confidence: confidenceFromCount(sub.length)
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
var ALIGNMENT_EXTRACTOR = {
|
|
842
|
+
id: "alignment",
|
|
843
|
+
description: "Coordination pressure \u2014 fraction of events that reference a prior event",
|
|
844
|
+
extract(events, domain) {
|
|
845
|
+
const sub = inDomain(events, domain);
|
|
846
|
+
if (sub.length === 0) return ZERO;
|
|
847
|
+
const referencing = sub.filter((e) => e.event.respondsTo !== void 0).length;
|
|
848
|
+
return {
|
|
849
|
+
score: clamp100(referencing / sub.length * 100),
|
|
850
|
+
eventCount: sub.length,
|
|
851
|
+
confidence: confidenceFromCount(sub.length)
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
var DECISION_MOMENTUM_EXTRACTOR = {
|
|
856
|
+
id: "decision_momentum",
|
|
857
|
+
description: "Rate of activity in this domain \u2014 events per day, capped at 10/day",
|
|
858
|
+
extract(events, domain) {
|
|
859
|
+
const sub = inDomain(events, domain);
|
|
860
|
+
if (sub.length === 0) return ZERO;
|
|
861
|
+
if (sub.length < 2) {
|
|
862
|
+
return {
|
|
863
|
+
score: 20,
|
|
864
|
+
// token non-zero score — single event = some motion
|
|
865
|
+
eventCount: sub.length,
|
|
866
|
+
confidence: confidenceFromCount(sub.length)
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
const ts = sub.map((e) => Date.parse(e.event.timestamp)).sort((a, b) => a - b);
|
|
870
|
+
const spanMs = ts[ts.length - 1] - ts[0];
|
|
871
|
+
const spanDays = Math.max(spanMs / (24 * 60 * 60 * 1e3), 1 / 24);
|
|
872
|
+
const perDay = sub.length / spanDays;
|
|
873
|
+
const normalized = Math.min(perDay, 10) / 10;
|
|
874
|
+
return {
|
|
875
|
+
score: clamp100(normalized * 100),
|
|
876
|
+
eventCount: sub.length,
|
|
877
|
+
confidence: confidenceFromCount(sub.length)
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
var DEFAULT_SIGNAL_EXTRACTORS = Object.freeze([
|
|
882
|
+
CLARITY_EXTRACTOR,
|
|
883
|
+
OWNERSHIP_EXTRACTOR,
|
|
884
|
+
FOLLOW_THROUGH_EXTRACTOR,
|
|
885
|
+
ALIGNMENT_EXTRACTOR,
|
|
886
|
+
DECISION_MOMENTUM_EXTRACTOR
|
|
887
|
+
]);
|
|
888
|
+
|
|
889
|
+
// src/radiant/types.ts
|
|
890
|
+
var DEFAULT_EVIDENCE_GATE = { k: 3, c: 0.5 };
|
|
891
|
+
function isScored(s) {
|
|
892
|
+
return typeof s === "number";
|
|
893
|
+
}
|
|
894
|
+
function isSentinel(s) {
|
|
895
|
+
return typeof s === "string";
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// src/radiant/core/math.ts
|
|
899
|
+
function isPresent(o, gate = DEFAULT_EVIDENCE_GATE) {
|
|
900
|
+
return o.eventCount >= gate.k && o.confidence >= gate.c;
|
|
901
|
+
}
|
|
902
|
+
function presenceAverage(items, gate = DEFAULT_EVIDENCE_GATE) {
|
|
903
|
+
const present = items.filter((i) => isPresent(i, gate));
|
|
904
|
+
if (present.length === 0) return "INSUFFICIENT_EVIDENCE";
|
|
905
|
+
const sum = present.reduce((acc, i) => acc + i.score, 0);
|
|
906
|
+
return sum / present.length;
|
|
907
|
+
}
|
|
908
|
+
function scoreLife(capability, gate = DEFAULT_EVIDENCE_GATE) {
|
|
909
|
+
return presenceAverage(capability.dimensions, gate);
|
|
910
|
+
}
|
|
911
|
+
function scoreCyber(capability, gate = DEFAULT_EVIDENCE_GATE) {
|
|
912
|
+
return presenceAverage(capability.dimensions, gate);
|
|
913
|
+
}
|
|
914
|
+
function scoreNeuroVerse(components, worldmodelLoaded, gate = DEFAULT_EVIDENCE_GATE) {
|
|
915
|
+
if (!worldmodelLoaded) return "UNAVAILABLE";
|
|
916
|
+
return presenceAverage(components, gate);
|
|
917
|
+
}
|
|
918
|
+
function scoreComposite(a_L, a_C, a_N) {
|
|
919
|
+
const available = [];
|
|
920
|
+
if (isScored(a_L)) available.push(a_L);
|
|
921
|
+
if (isScored(a_C)) available.push(a_C);
|
|
922
|
+
if (isScored(a_N)) available.push(a_N);
|
|
923
|
+
if (available.length === 0) return "INSUFFICIENT_EVIDENCE";
|
|
924
|
+
return available.reduce((a, b) => a + b, 0) / available.length;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// src/radiant/core/patterns.ts
|
|
928
|
+
async function interpretPatterns(input) {
|
|
929
|
+
const prompt = buildInterpretationPrompt(input);
|
|
930
|
+
const raw = await input.ai.complete(prompt, "Analyze the activity and produce the read.");
|
|
931
|
+
const parsed = parseInterpretation(raw, input.canonicalPatterns ?? []);
|
|
932
|
+
return {
|
|
933
|
+
patterns: parsed.patterns,
|
|
934
|
+
meaning: parsed.meaning,
|
|
935
|
+
move: parsed.move,
|
|
936
|
+
raw_ai_response: raw
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
function buildInterpretationPrompt(input) {
|
|
940
|
+
const signalSummary = formatSignalSummary(input.signals);
|
|
941
|
+
const eventSample = formatEventSample(input.events, 30);
|
|
942
|
+
const canonicalList = (input.canonicalPatterns ?? []).length > 0 ? `Patterns the organization has already named (use these names if you see them):
|
|
943
|
+
${input.canonicalPatterns.map((p) => `- ${p}`).join("\n")}` : "No patterns have been named yet. Everything you observe is new.";
|
|
944
|
+
const frame = input.lens.primary_frame;
|
|
945
|
+
const evalQuestions = frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n");
|
|
946
|
+
const forbiddenList = input.lens.forbidden_phrases.map((p) => `- "${p}"`).join("\n");
|
|
947
|
+
const jargonTable = Object.entries(input.lens.vocabulary.jargon_translations).map(([internal, plain]) => ` "${internal}" \u2192 "${plain}"`).join("\n");
|
|
948
|
+
return `You are a behavioral intelligence system reading team activity and producing a read for the reader who needs to act on it.
|
|
949
|
+
|
|
950
|
+
## Context the reader has loaded
|
|
951
|
+
|
|
952
|
+
${input.worldmodelContent}
|
|
953
|
+
|
|
954
|
+
## What happened this window
|
|
955
|
+
|
|
956
|
+
### Signal matrix (what Radiant measured)
|
|
957
|
+
|
|
958
|
+
${signalSummary}
|
|
959
|
+
|
|
960
|
+
### Recent events (sample)
|
|
961
|
+
|
|
962
|
+
${eventSample}
|
|
963
|
+
|
|
964
|
+
## How to reason
|
|
965
|
+
|
|
966
|
+
Reason through these questions INTERNALLY \u2014 do not list them in your output:
|
|
967
|
+
|
|
968
|
+
${evalQuestions}
|
|
969
|
+
|
|
970
|
+
Scoring rubric: ${frame.scoring_rubric}
|
|
971
|
+
|
|
972
|
+
${canonicalList}
|
|
973
|
+
|
|
974
|
+
${input.statedIntent ? input.statedIntent + "\n" : ""}## Voice: speak like an Auki builder, not like a status report
|
|
975
|
+
|
|
976
|
+
The reader wants to know **what this means and what to do**, not "what happened." Frame every observation as consequence + implication, not just description.
|
|
977
|
+
|
|
978
|
+
Wrong voice (status report):
|
|
979
|
+
"Rapid deployment of complex technical architecture through composable commits."
|
|
980
|
+
"Signal extraction across life, cyber, and joint domains enables consistent behavioral analysis."
|
|
981
|
+
"Decision momentum scores suggest architectural delivery without corresponding strategic direction setting."
|
|
982
|
+
|
|
983
|
+
Right voice (Auki builder):
|
|
984
|
+
"Shipping pace is high. The architecture is getting ahead of strategic decisions \u2014 velocity without a declared target."
|
|
985
|
+
"Every pattern is new. Nothing is being tracked by name yet. That's fine for now; it becomes a problem when patterns repeat and you still don't have vocabulary for them."
|
|
986
|
+
"The work is converging across three modules. The story of HOW they compose isn't being told yet."
|
|
987
|
+
|
|
988
|
+
The difference: consequence in plain English, not observation in system vocabulary.
|
|
989
|
+
|
|
990
|
+
## Translate internal jargon to plain English
|
|
991
|
+
|
|
992
|
+
Readers don't know Radiant's vocabulary. Before ANY description appears in your output, translate these:
|
|
993
|
+
|
|
994
|
+
${jargonTable}
|
|
995
|
+
|
|
996
|
+
For example: don't say "update the worldmodel." Say "add a line to your strategy file."
|
|
997
|
+
|
|
998
|
+
## Health is a valid read
|
|
999
|
+
|
|
1000
|
+
If the activity is healthy and aligned with the worldmodel, SAY SO. Don't fabricate problems. Over-prescription is a voice failure. Legitimate outputs include:
|
|
1001
|
+
|
|
1002
|
+
"Nothing's broken. Keep shipping."
|
|
1003
|
+
"This is what healthy looks like \u2014 the invariants are holding."
|
|
1004
|
+
"Nothing here needs action."
|
|
1005
|
+
|
|
1006
|
+
Only recommend a move when the evidence actually calls for one.
|
|
1007
|
+
|
|
1008
|
+
## Output schema \u2014 JSON object
|
|
1009
|
+
|
|
1010
|
+
\`\`\`json
|
|
1011
|
+
{
|
|
1012
|
+
"patterns": [
|
|
1013
|
+
{
|
|
1014
|
+
"name": "pattern_name_snake_case",
|
|
1015
|
+
"type": "canonical" | "candidate",
|
|
1016
|
+
"description": "Consequence-framed, plain-English, 1-2 sentences. The reader understands why this matters, not just what you observed.",
|
|
1017
|
+
"evidence": {
|
|
1018
|
+
"signals": ["signal_id.domain", ...],
|
|
1019
|
+
"events": ["event_id", ...],
|
|
1020
|
+
"cited_invariant": "invariant_name_or_null"
|
|
1021
|
+
},
|
|
1022
|
+
"confidence": 0.0 to 1.0
|
|
1023
|
+
}
|
|
1024
|
+
],
|
|
1025
|
+
"meaning": "3-5 sentences. Weave the patterns into ONE strategic thesis. Compress. The reader should finish this paragraph and understand the one thing that matters most in this read. Plain English \u2014 no system jargon.",
|
|
1026
|
+
"move": "1-3 direct imperatives, OR explicit 'nothing to act on' if the read is healthy. Do not fabricate urgency. When a candidate pattern has high confidence (>0.6), tell the reader EXACTLY where to declare it: 'If you want Radiant to track [pattern_name] over time, add it to auki-strategy.worldmodel.md under Evolution Layer \u2192 Drift Behaviors (or Aligned Behaviors if it is positive). If you don't, Radiant will rediscover it from scratch next run.' Be specific about the file and section \u2014 don't make them guess."
|
|
1027
|
+
}
|
|
1028
|
+
\`\`\`
|
|
1029
|
+
|
|
1030
|
+
## Hard rules
|
|
1031
|
+
|
|
1032
|
+
- Every signal you cite MUST appear in the signal matrix above
|
|
1033
|
+
- Every event you cite MUST appear in the events sample above
|
|
1034
|
+
- Do not invent signals or events that aren't in the data
|
|
1035
|
+
- Candidate patterns must have type "candidate"
|
|
1036
|
+
- No hedging, no hype vocabulary
|
|
1037
|
+
- Apply jargon translation before output
|
|
1038
|
+
- Health-is-valid \u2014 don't invent problems
|
|
1039
|
+
- Return ONLY the JSON object, no other text
|
|
1040
|
+
|
|
1041
|
+
Do NOT use these phrases anywhere in your output:
|
|
1042
|
+
${forbiddenList}`;
|
|
1043
|
+
}
|
|
1044
|
+
function formatSignalSummary(signals) {
|
|
1045
|
+
const lines = [];
|
|
1046
|
+
const domains = ["life", "cyber", "joint"];
|
|
1047
|
+
for (const domain of domains) {
|
|
1048
|
+
const domainSignals = signals.filter((s) => s.domain === domain);
|
|
1049
|
+
if (domainSignals.length === 0) continue;
|
|
1050
|
+
lines.push(`### ${domain}`);
|
|
1051
|
+
for (const s of domainSignals) {
|
|
1052
|
+
const gate = s.eventCount >= 3 && s.confidence >= 0.5 ? "\u2713" : "\u25CB";
|
|
1053
|
+
lines.push(
|
|
1054
|
+
` ${gate} ${s.id}: score=${s.score.toFixed(1)}, events=${s.eventCount}, conf=${s.confidence.toFixed(2)}`
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return lines.join("\n");
|
|
1059
|
+
}
|
|
1060
|
+
function formatEventSample(events, maxEvents) {
|
|
1061
|
+
const sample = events.slice(-maxEvents);
|
|
1062
|
+
return sample.map((e) => {
|
|
1063
|
+
const content = (e.event.content ?? "").slice(0, 200);
|
|
1064
|
+
const respondsTo = e.event.respondsTo ? ` (responds to ${e.event.respondsTo.eventId})` : "";
|
|
1065
|
+
return `- [${e.domain}] ${e.event.id} | ${e.event.actor.kind}:${e.event.actor.id} | ${e.event.kind ?? "event"}${respondsTo}
|
|
1066
|
+
"${content}"`;
|
|
1067
|
+
}).join("\n");
|
|
1068
|
+
}
|
|
1069
|
+
function parseInterpretation(raw, canonicalNames) {
|
|
1070
|
+
let meaning = "";
|
|
1071
|
+
let move = "";
|
|
1072
|
+
let patternsArray = [];
|
|
1073
|
+
const objMatch = raw.match(/\{[\s\S]*"patterns"[\s\S]*\}/);
|
|
1074
|
+
if (objMatch) {
|
|
1075
|
+
try {
|
|
1076
|
+
const obj = JSON.parse(objMatch[0]);
|
|
1077
|
+
if (Array.isArray(obj.patterns)) {
|
|
1078
|
+
patternsArray = obj.patterns;
|
|
1079
|
+
}
|
|
1080
|
+
if (typeof obj.meaning === "string") meaning = obj.meaning;
|
|
1081
|
+
if (typeof obj.move === "string") move = obj.move;
|
|
1082
|
+
} catch {
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (patternsArray.length === 0) {
|
|
1086
|
+
const arrMatch = raw.match(/\[[\s\S]*\]/);
|
|
1087
|
+
if (arrMatch) {
|
|
1088
|
+
try {
|
|
1089
|
+
const arr = JSON.parse(arrMatch[0]);
|
|
1090
|
+
if (Array.isArray(arr)) patternsArray = arr;
|
|
1091
|
+
} catch {
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const canonicalSet = new Set(canonicalNames.map((n) => n.toLowerCase()));
|
|
1096
|
+
const patterns = [];
|
|
1097
|
+
for (const item of patternsArray) {
|
|
1098
|
+
if (!isPatternLike(item)) continue;
|
|
1099
|
+
const nameStr = String(item.name ?? "unnamed");
|
|
1100
|
+
const ev = item.evidence;
|
|
1101
|
+
const isCanonical = item.type === "canonical" || canonicalSet.has(nameStr.toLowerCase());
|
|
1102
|
+
patterns.push({
|
|
1103
|
+
name: nameStr,
|
|
1104
|
+
type: isCanonical ? "canonical" : "candidate",
|
|
1105
|
+
declaredAs: isCanonical ? nameStr : void 0,
|
|
1106
|
+
description: String(item.description ?? ""),
|
|
1107
|
+
evidence: {
|
|
1108
|
+
signals: Array.isArray(ev?.signals) ? ev.signals.map(String) : [],
|
|
1109
|
+
events: Array.isArray(ev?.events) ? ev.events.map(String) : [],
|
|
1110
|
+
cited_invariant: ev?.cited_invariant ? String(ev.cited_invariant) : void 0
|
|
1111
|
+
},
|
|
1112
|
+
confidence: typeof item.confidence === "number" ? Math.max(0, Math.min(1, item.confidence)) : 0.5
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
return { patterns, meaning, move };
|
|
1116
|
+
}
|
|
1117
|
+
function isPatternLike(x) {
|
|
1118
|
+
return typeof x === "object" && x !== null && "name" in x;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// src/radiant/core/renderer.ts
|
|
1122
|
+
function render(input) {
|
|
1123
|
+
const text = renderText(input);
|
|
1124
|
+
const frontmatter = renderFrontmatter(input);
|
|
1125
|
+
return { text, frontmatter };
|
|
1126
|
+
}
|
|
1127
|
+
function renderText(input) {
|
|
1128
|
+
const sections = [];
|
|
1129
|
+
sections.push(
|
|
1130
|
+
`Scope: ${formatScope(input.scope)}
|
|
1131
|
+
Window: last ${input.windowDays} days \xB7 ${input.eventCount} events
|
|
1132
|
+
Lens: ${input.lens.name}`
|
|
1133
|
+
);
|
|
1134
|
+
if (input.patterns.length > 0) {
|
|
1135
|
+
const canonical = input.patterns.filter((p) => p.type === "canonical");
|
|
1136
|
+
const candidates = input.patterns.filter((p) => p.type === "candidate");
|
|
1137
|
+
let emergentBlock = "EMERGENT\n";
|
|
1138
|
+
if (canonical.length > 0) {
|
|
1139
|
+
for (const p of canonical) {
|
|
1140
|
+
emergentBlock += `
|
|
1141
|
+
${p.name}
|
|
1142
|
+
`;
|
|
1143
|
+
emergentBlock += ` ${p.description}
|
|
1144
|
+
`;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
if (candidates.length > 0) {
|
|
1148
|
+
emergentBlock += "\n Emergent (candidates \u2014 not yet in worldmodel)\n";
|
|
1149
|
+
for (const p of candidates) {
|
|
1150
|
+
emergentBlock += `
|
|
1151
|
+
${p.name} (candidate)
|
|
1152
|
+
`;
|
|
1153
|
+
emergentBlock += ` ${p.description}
|
|
1154
|
+
`;
|
|
1155
|
+
if (p.evidence.cited_invariant) {
|
|
1156
|
+
emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
|
|
1157
|
+
`;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
sections.push(emergentBlock.trimEnd());
|
|
1162
|
+
}
|
|
1163
|
+
if (input.meaning) {
|
|
1164
|
+
sections.push(`MEANING
|
|
1165
|
+
|
|
1166
|
+
${input.meaning.split("\n").join("\n ")}`);
|
|
1167
|
+
}
|
|
1168
|
+
if (input.move) {
|
|
1169
|
+
sections.push(`MOVE
|
|
1170
|
+
|
|
1171
|
+
${input.move.split("\n").join("\n ")}`);
|
|
1172
|
+
}
|
|
1173
|
+
const alignBlock = [
|
|
1174
|
+
"ALIGNMENT",
|
|
1175
|
+
"",
|
|
1176
|
+
` Human work: ${formatScore(input.scores.A_L)}`,
|
|
1177
|
+
` AI work: ${formatScore(input.scores.A_C)}`,
|
|
1178
|
+
` Human\u2013AI collaboration: ${formatScore(input.scores.A_N)}`,
|
|
1179
|
+
` Composite: ${formatScore(input.scores.R)}`
|
|
1180
|
+
].join("\n");
|
|
1181
|
+
sections.push(alignBlock);
|
|
1182
|
+
if (input.governance && input.governance.totalEvents > 0) {
|
|
1183
|
+
const gov = input.governance;
|
|
1184
|
+
const govLines = ["GOVERNANCE", "", ` ${gov.summary}`];
|
|
1185
|
+
const showSide = (label, side) => {
|
|
1186
|
+
if (side.allow + side.modify + side.block === 0) return;
|
|
1187
|
+
govLines.push("");
|
|
1188
|
+
govLines.push(` ${label}:`);
|
|
1189
|
+
govLines.push(` ${side.allow} ALLOW \xB7 ${side.modify} MODIFY \xB7 ${side.block} BLOCK`);
|
|
1190
|
+
for (const d of side.details.slice(0, 3)) {
|
|
1191
|
+
const reason = d.reason ? ` \u2192 ${d.reason}` : "";
|
|
1192
|
+
govLines.push(` ${d.status}: ${d.eventId}${reason}`);
|
|
1193
|
+
}
|
|
1194
|
+
if (side.details.length > 3) {
|
|
1195
|
+
govLines.push(` ... and ${side.details.length - 3} more`);
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
showSide("Human side", gov.human);
|
|
1199
|
+
showSide("AI side", gov.cyber);
|
|
1200
|
+
showSide("Human\u2013AI joint", gov.joint);
|
|
1201
|
+
sections.push(govLines.join("\n"));
|
|
1202
|
+
}
|
|
1203
|
+
sections.push(renderDepth(input.priorReadCount ?? 0, input.windowDays));
|
|
1204
|
+
return sections.join("\n\n");
|
|
1205
|
+
}
|
|
1206
|
+
function renderDepth(priorReads, windowDays) {
|
|
1207
|
+
if (priorReads === 0) {
|
|
1208
|
+
return [
|
|
1209
|
+
"DEPTH",
|
|
1210
|
+
"",
|
|
1211
|
+
` This is your first read. Radiant sees ${windowDays} days of activity`,
|
|
1212
|
+
" but has no prior baseline to compare against.",
|
|
1213
|
+
"",
|
|
1214
|
+
" Available now:",
|
|
1215
|
+
" \u2713 Signal extraction across life / cyber / joint domains",
|
|
1216
|
+
" \u2713 Pattern identification (canonical + candidates)",
|
|
1217
|
+
" \u2713 Alignment scoring",
|
|
1218
|
+
"",
|
|
1219
|
+
" Available after 2+ reads:",
|
|
1220
|
+
" \xB7 Drift detection (is alignment improving or degrading?)",
|
|
1221
|
+
' \xB7 Baselines (what does "normal" look like for this team?)',
|
|
1222
|
+
" \xB7 Pattern confidence (are these patterns persistent or noise?)",
|
|
1223
|
+
" \xB7 Evolution proposals (should the worldmodel adapt?)",
|
|
1224
|
+
"",
|
|
1225
|
+
" Run again next week. The read gets sharper every time."
|
|
1226
|
+
].join("\n");
|
|
1227
|
+
}
|
|
1228
|
+
if (priorReads < 4) {
|
|
1229
|
+
return [
|
|
1230
|
+
"DEPTH",
|
|
1231
|
+
"",
|
|
1232
|
+
` Read ${priorReads + 1} of this scope. Baseline forming.`,
|
|
1233
|
+
"",
|
|
1234
|
+
" Available now:",
|
|
1235
|
+
" \u2713 Signal extraction + pattern identification + alignment scoring",
|
|
1236
|
+
` \u2713 Drift detection (comparing against ${priorReads} prior read${priorReads > 1 ? "s" : ""})`,
|
|
1237
|
+
" \xB7 Baselines stabilizing (need 4+ reads for reliable averages)",
|
|
1238
|
+
" \xB7 Pattern confidence accumulating",
|
|
1239
|
+
"",
|
|
1240
|
+
" The read sharpens with each run."
|
|
1241
|
+
].join("\n");
|
|
1242
|
+
}
|
|
1243
|
+
return [
|
|
1244
|
+
"DEPTH",
|
|
1245
|
+
"",
|
|
1246
|
+
` Read ${priorReads + 1} of this scope. Baseline established.`,
|
|
1247
|
+
"",
|
|
1248
|
+
" Available:",
|
|
1249
|
+
" \u2713 Signal extraction + pattern identification + alignment scoring",
|
|
1250
|
+
" \u2713 Drift detection against established baseline",
|
|
1251
|
+
" \u2713 Pattern confidence (persistent vs noise)",
|
|
1252
|
+
" \u2713 Evolution proposals (candidate patterns with enough history to evaluate)"
|
|
1253
|
+
].join("\n");
|
|
1254
|
+
}
|
|
1255
|
+
function formatScore(s) {
|
|
1256
|
+
if (!isScored(s)) {
|
|
1257
|
+
if (s === "UNAVAILABLE") return "not available (no worldmodel loaded)";
|
|
1258
|
+
return "not enough signal to call yet";
|
|
1259
|
+
}
|
|
1260
|
+
const n = Math.round(s);
|
|
1261
|
+
let label;
|
|
1262
|
+
if (n >= 75) label = "STRONG";
|
|
1263
|
+
else if (n >= 60) label = "STABLE";
|
|
1264
|
+
else if (n >= 45) label = "needs attention";
|
|
1265
|
+
else if (n >= 30) label = "concerning";
|
|
1266
|
+
else label = "critical";
|
|
1267
|
+
return `${n} \xB7 ${label}`;
|
|
1268
|
+
}
|
|
1269
|
+
function renderFrontmatter(input) {
|
|
1270
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1271
|
+
const signalsByDomain = groupSignalsByDomain(input.signals);
|
|
1272
|
+
const patternEntries = input.patterns.map((p) => {
|
|
1273
|
+
const entry = {
|
|
1274
|
+
name: p.name,
|
|
1275
|
+
type: p.type,
|
|
1276
|
+
conf: Number(p.confidence.toFixed(2)),
|
|
1277
|
+
evidence_signals: p.evidence.signals,
|
|
1278
|
+
evidence_events: p.evidence.events
|
|
1279
|
+
};
|
|
1280
|
+
if (p.evidence.cited_invariant) {
|
|
1281
|
+
entry.cited_invariant = p.evidence.cited_invariant;
|
|
1282
|
+
}
|
|
1283
|
+
return entry;
|
|
1284
|
+
});
|
|
1285
|
+
const frontmatter = {
|
|
1286
|
+
radiant_read: {
|
|
1287
|
+
scope: formatScope(input.scope),
|
|
1288
|
+
window: `${input.windowDays}d`,
|
|
1289
|
+
timestamp: now,
|
|
1290
|
+
lens: input.lens.name
|
|
1291
|
+
},
|
|
1292
|
+
events: {
|
|
1293
|
+
total: input.eventCount
|
|
1294
|
+
},
|
|
1295
|
+
signals: signalsByDomain,
|
|
1296
|
+
scores: {
|
|
1297
|
+
A_L: isScored(input.scores.A_L) ? Math.round(input.scores.A_L) : String(input.scores.A_L),
|
|
1298
|
+
A_C: isScored(input.scores.A_C) ? Math.round(input.scores.A_C) : String(input.scores.A_C),
|
|
1299
|
+
A_N: isScored(input.scores.A_N) ? Math.round(input.scores.A_N) : String(input.scores.A_N),
|
|
1300
|
+
R: isScored(input.scores.R) ? Math.round(input.scores.R) : String(input.scores.R)
|
|
1301
|
+
},
|
|
1302
|
+
patterns: patternEntries
|
|
1303
|
+
};
|
|
1304
|
+
return "---\n" + serializeYAML(frontmatter) + "---";
|
|
1305
|
+
}
|
|
1306
|
+
function groupSignalsByDomain(signals) {
|
|
1307
|
+
const result = {};
|
|
1308
|
+
for (const s of signals) {
|
|
1309
|
+
if (!result[s.domain]) result[s.domain] = {};
|
|
1310
|
+
result[s.domain][s.id] = {
|
|
1311
|
+
score: Number(s.score.toFixed(1)),
|
|
1312
|
+
n: s.eventCount,
|
|
1313
|
+
conf: Number(s.confidence.toFixed(2))
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
return result;
|
|
1317
|
+
}
|
|
1318
|
+
function serializeYAML(obj, indent = 0) {
|
|
1319
|
+
const pad = " ".repeat(indent);
|
|
1320
|
+
if (obj === null || obj === void 0) return "null\n";
|
|
1321
|
+
if (typeof obj === "string") return `${JSON.stringify(obj)}
|
|
1322
|
+
`;
|
|
1323
|
+
if (typeof obj === "number" || typeof obj === "boolean") return `${obj}
|
|
1324
|
+
`;
|
|
1325
|
+
if (Array.isArray(obj)) {
|
|
1326
|
+
if (obj.length === 0) return "[]\n";
|
|
1327
|
+
if (obj.every((item) => typeof item === "string" || typeof item === "number")) {
|
|
1328
|
+
return `[${obj.map((item) => JSON.stringify(item)).join(", ")}]
|
|
1329
|
+
`;
|
|
1330
|
+
}
|
|
1331
|
+
let result = "\n";
|
|
1332
|
+
for (const item of obj) {
|
|
1333
|
+
if (typeof item === "object" && item !== null && !Array.isArray(item)) {
|
|
1334
|
+
const entries = Object.entries(item);
|
|
1335
|
+
result += `${pad}- ${entries[0][0]}: ${serializeYAML(entries[0][1], 0).trim()}
|
|
1336
|
+
`;
|
|
1337
|
+
for (let i = 1; i < entries.length; i++) {
|
|
1338
|
+
result += `${pad} ${entries[i][0]}: ${serializeYAML(entries[i][1], indent + 2).trim()}
|
|
1339
|
+
`;
|
|
1340
|
+
}
|
|
1341
|
+
} else {
|
|
1342
|
+
result += `${pad}- ${serializeYAML(item, indent + 1).trim()}
|
|
1343
|
+
`;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
return result;
|
|
1347
|
+
}
|
|
1348
|
+
if (typeof obj === "object") {
|
|
1349
|
+
const entries = Object.entries(obj);
|
|
1350
|
+
if (entries.length === 0) return "{}\n";
|
|
1351
|
+
let result = "\n";
|
|
1352
|
+
for (const [key, value] of entries) {
|
|
1353
|
+
if (typeof value === "object" && value !== null) {
|
|
1354
|
+
result += `${pad}${key}:${serializeYAML(value, indent + 1)}`;
|
|
1355
|
+
} else {
|
|
1356
|
+
result += `${pad}${key}: ${serializeYAML(value, indent).trim()}
|
|
1357
|
+
`;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
return result;
|
|
1361
|
+
}
|
|
1362
|
+
return `${obj}
|
|
1363
|
+
`;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
// src/radiant/commands/emergent.ts
|
|
1367
|
+
async function emergent(input) {
|
|
1368
|
+
const lens = resolveLens2(input.lensId);
|
|
1369
|
+
const windowDays = input.windowDays ?? 14;
|
|
1370
|
+
let statedIntent;
|
|
1371
|
+
let exocortexContext;
|
|
1372
|
+
let priorReadContext = "";
|
|
1373
|
+
if (input.exocortexPath) {
|
|
1374
|
+
exocortexContext = readExocortex(input.exocortexPath);
|
|
1375
|
+
const formatted = formatExocortexForPrompt(exocortexContext);
|
|
1376
|
+
if (formatted) statedIntent = formatted;
|
|
1377
|
+
const priorReads = loadPriorReads(input.exocortexPath);
|
|
1378
|
+
if (priorReads.length > 0) {
|
|
1379
|
+
priorReadContext = formatPriorReadsForPrompt(priorReads);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
const events = await fetchGitHubActivity(input.scope, input.githubToken, {
|
|
1383
|
+
windowDays
|
|
1384
|
+
});
|
|
1385
|
+
const classified = classifyEvents(events);
|
|
1386
|
+
const signals = extractSignals(classified);
|
|
1387
|
+
const scores = computeScores(signals, input.worldmodelContent !== "");
|
|
1388
|
+
const { patterns, meaning, move } = await interpretPatterns({
|
|
1389
|
+
signals,
|
|
1390
|
+
events: classified,
|
|
1391
|
+
worldmodelContent: input.worldmodelContent,
|
|
1392
|
+
lens,
|
|
1393
|
+
ai: input.ai,
|
|
1394
|
+
canonicalPatterns: input.canonicalPatterns,
|
|
1395
|
+
statedIntent: statedIntent ? statedIntent + (priorReadContext ? "\n\n" + priorReadContext : "") : priorReadContext || void 0
|
|
1396
|
+
});
|
|
1397
|
+
const rewrittenPatterns = patterns.map((p) => lens.rewrite(p));
|
|
1398
|
+
const allDescriptions = rewrittenPatterns.map((p) => p.description).join("\n");
|
|
1399
|
+
const voiceViolations = checkForbiddenPhrases(lens, allDescriptions);
|
|
1400
|
+
let governance;
|
|
1401
|
+
if (input.worldPath) {
|
|
1402
|
+
try {
|
|
1403
|
+
governance = await auditGovernance(classified, input.worldPath);
|
|
1404
|
+
} catch {
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
const rendered = render({
|
|
1408
|
+
scope: input.scope,
|
|
1409
|
+
windowDays,
|
|
1410
|
+
eventCount: events.length,
|
|
1411
|
+
signals,
|
|
1412
|
+
patterns: rewrittenPatterns,
|
|
1413
|
+
scores,
|
|
1414
|
+
lens,
|
|
1415
|
+
meaning: meaning || void 0,
|
|
1416
|
+
move: move || void 0,
|
|
1417
|
+
governance
|
|
1418
|
+
});
|
|
1419
|
+
if (input.exocortexPath) {
|
|
1420
|
+
try {
|
|
1421
|
+
const readPath = writeRead(input.exocortexPath, rendered.frontmatter, rendered.text);
|
|
1422
|
+
const priorReads = loadPriorReads(input.exocortexPath);
|
|
1423
|
+
const currentPatternNames = rewrittenPatterns.map((p) => p.name);
|
|
1424
|
+
const persistence = computePersistence(priorReads, currentPatternNames);
|
|
1425
|
+
const triggeredItems = governance ? [
|
|
1426
|
+
...governance.human.details.map((d) => d.ruleId).filter(Boolean),
|
|
1427
|
+
...governance.cyber.details.map((d) => d.ruleId).filter(Boolean),
|
|
1428
|
+
...governance.joint.details.map((d) => d.ruleId).filter(Boolean)
|
|
1429
|
+
] : [];
|
|
1430
|
+
updateKnowledge(input.exocortexPath, persistence, {
|
|
1431
|
+
triggeredItems,
|
|
1432
|
+
totalReads: priorReads.length + 1
|
|
1433
|
+
});
|
|
1434
|
+
} catch {
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return {
|
|
1438
|
+
text: rendered.text,
|
|
1439
|
+
frontmatter: rendered.frontmatter,
|
|
1440
|
+
voiceViolations,
|
|
1441
|
+
voiceClean: voiceViolations.length === 0,
|
|
1442
|
+
signals,
|
|
1443
|
+
scores,
|
|
1444
|
+
eventCount: events.length
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
function computeScores(signals, worldmodelLoaded) {
|
|
1448
|
+
const gate = DEFAULT_EVIDENCE_GATE;
|
|
1449
|
+
const lifeSignals = signals.filter((s) => s.domain === "life");
|
|
1450
|
+
const A_L = scoreLife(
|
|
1451
|
+
{ dimensions: lifeSignals.map(signalToDimension) },
|
|
1452
|
+
gate
|
|
1453
|
+
);
|
|
1454
|
+
const cyberSignals = signals.filter((s) => s.domain === "cyber");
|
|
1455
|
+
const A_C = scoreCyber(
|
|
1456
|
+
{ dimensions: cyberSignals.map(signalToDimension) },
|
|
1457
|
+
gate
|
|
1458
|
+
);
|
|
1459
|
+
const jointSignals = signals.filter((s) => s.domain === "joint");
|
|
1460
|
+
const A_N = scoreNeuroVerse(
|
|
1461
|
+
jointSignals.map(signalToBridging),
|
|
1462
|
+
worldmodelLoaded,
|
|
1463
|
+
gate
|
|
1464
|
+
);
|
|
1465
|
+
const R = scoreComposite(A_L, A_C, A_N);
|
|
1466
|
+
return { A_L, A_C, A_N, R };
|
|
1467
|
+
}
|
|
1468
|
+
function signalToDimension(s) {
|
|
1469
|
+
return {
|
|
1470
|
+
id: s.id,
|
|
1471
|
+
score: s.score,
|
|
1472
|
+
eventCount: s.eventCount,
|
|
1473
|
+
confidence: s.confidence
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
function signalToBridging(s) {
|
|
1477
|
+
return {
|
|
1478
|
+
component: "ALIGN",
|
|
1479
|
+
// Proxy: joint signals → ALIGN component
|
|
1480
|
+
score: s.score,
|
|
1481
|
+
eventCount: s.eventCount,
|
|
1482
|
+
confidence: s.confidence
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
function resolveLens2(id) {
|
|
1486
|
+
const lens = getLens(id);
|
|
1487
|
+
if (!lens) {
|
|
1488
|
+
throw new Error(
|
|
1489
|
+
`Lens "${id}" not found. Check the id or register the lens.`
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
return lens;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/radiant/core/ai.ts
|
|
1496
|
+
function createAnthropicAI(apiKey, model = "claude-sonnet-4-20250514", maxTokens = 4096) {
|
|
1497
|
+
return {
|
|
1498
|
+
async complete(systemPrompt, userQuery) {
|
|
1499
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1500
|
+
method: "POST",
|
|
1501
|
+
headers: {
|
|
1502
|
+
"x-api-key": apiKey,
|
|
1503
|
+
"anthropic-version": "2023-06-01",
|
|
1504
|
+
"content-type": "application/json"
|
|
1505
|
+
},
|
|
1506
|
+
body: JSON.stringify({
|
|
1507
|
+
model,
|
|
1508
|
+
max_tokens: maxTokens,
|
|
1509
|
+
system: systemPrompt,
|
|
1510
|
+
messages: [{ role: "user", content: userQuery }]
|
|
1511
|
+
})
|
|
1512
|
+
});
|
|
1513
|
+
if (!res.ok) {
|
|
1514
|
+
const body = await res.text();
|
|
1515
|
+
throw new Error(
|
|
1516
|
+
`Anthropic API error ${res.status}: ${body.slice(0, 500)}`
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
const data = await res.json();
|
|
1520
|
+
const text = data.content?.filter((c) => c.type === "text").map((c) => c.text ?? "").join("");
|
|
1521
|
+
if (!text) {
|
|
1522
|
+
throw new Error("Anthropic returned no text content");
|
|
1523
|
+
}
|
|
1524
|
+
return text;
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
function createMockAI(fixedResponse) {
|
|
1529
|
+
return {
|
|
1530
|
+
async complete() {
|
|
1531
|
+
return fixedResponse;
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
export {
|
|
1537
|
+
composeSystemPrompt,
|
|
1538
|
+
checkForbiddenPhrases,
|
|
1539
|
+
think,
|
|
1540
|
+
parseRepoScope,
|
|
1541
|
+
formatScope,
|
|
1542
|
+
fetchGitHubActivity,
|
|
1543
|
+
createMockGitHubAdapter,
|
|
1544
|
+
readExocortex,
|
|
1545
|
+
formatExocortexForPrompt,
|
|
1546
|
+
summarizeExocortex,
|
|
1547
|
+
writeRead,
|
|
1548
|
+
updateKnowledge,
|
|
1549
|
+
loadPriorReads,
|
|
1550
|
+
computePersistence,
|
|
1551
|
+
formatPriorReadsForPrompt,
|
|
1552
|
+
auditGovernance,
|
|
1553
|
+
classifyActorDomain,
|
|
1554
|
+
classifyEvents,
|
|
1555
|
+
extractSignals,
|
|
1556
|
+
DEFAULT_SIGNAL_EXTRACTORS,
|
|
1557
|
+
DEFAULT_EVIDENCE_GATE,
|
|
1558
|
+
isScored,
|
|
1559
|
+
isSentinel,
|
|
1560
|
+
isPresent,
|
|
1561
|
+
presenceAverage,
|
|
1562
|
+
scoreLife,
|
|
1563
|
+
scoreCyber,
|
|
1564
|
+
scoreNeuroVerse,
|
|
1565
|
+
scoreComposite,
|
|
1566
|
+
interpretPatterns,
|
|
1567
|
+
render,
|
|
1568
|
+
emergent,
|
|
1569
|
+
createAnthropicAI,
|
|
1570
|
+
createMockAI
|
|
1571
|
+
};
|