@neuroverseos/governance 0.10.0 → 0.12.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.
Files changed (95) hide show
  1. package/dist/adapters/autoresearch.cjs +19 -1
  2. package/dist/adapters/autoresearch.d.cts +1 -1
  3. package/dist/adapters/autoresearch.d.ts +1 -1
  4. package/dist/adapters/autoresearch.js +2 -2
  5. package/dist/adapters/deep-agents.cjs +19 -1
  6. package/dist/adapters/deep-agents.d.cts +2 -2
  7. package/dist/adapters/deep-agents.d.ts +2 -2
  8. package/dist/adapters/deep-agents.js +2 -2
  9. package/dist/adapters/express.cjs +19 -1
  10. package/dist/adapters/express.d.cts +1 -1
  11. package/dist/adapters/express.d.ts +1 -1
  12. package/dist/adapters/express.js +2 -2
  13. package/dist/adapters/github.cjs +19 -1
  14. package/dist/adapters/github.d.cts +2 -2
  15. package/dist/adapters/github.d.ts +2 -2
  16. package/dist/adapters/github.js +2 -2
  17. package/dist/adapters/index.cjs +19 -1
  18. package/dist/adapters/index.d.cts +2 -2
  19. package/dist/adapters/index.d.ts +2 -2
  20. package/dist/adapters/index.js +8 -8
  21. package/dist/adapters/langchain.cjs +19 -1
  22. package/dist/adapters/langchain.d.cts +2 -2
  23. package/dist/adapters/langchain.d.ts +2 -2
  24. package/dist/adapters/langchain.js +2 -2
  25. package/dist/adapters/mentraos.cjs +19 -1
  26. package/dist/adapters/mentraos.d.cts +2 -2
  27. package/dist/adapters/mentraos.d.ts +2 -2
  28. package/dist/adapters/mentraos.js +2 -2
  29. package/dist/adapters/openai.cjs +19 -1
  30. package/dist/adapters/openai.d.cts +2 -2
  31. package/dist/adapters/openai.d.ts +2 -2
  32. package/dist/adapters/openai.js +2 -2
  33. package/dist/adapters/openclaw.cjs +19 -1
  34. package/dist/adapters/openclaw.d.cts +2 -2
  35. package/dist/adapters/openclaw.d.ts +2 -2
  36. package/dist/adapters/openclaw.js +2 -2
  37. package/dist/admin/index.cjs +19 -1
  38. package/dist/admin/index.js +1 -1
  39. package/dist/audit-JYNN3MOQ.js +98 -0
  40. package/dist/audit-behavior-C62FdRAC.d.cts +100 -0
  41. package/dist/audit-behavior-DFy7LeYv.d.ts +100 -0
  42. package/dist/{behavioral-SPWPGYXL.js → behavioral-4TKMHZQZ.js} +2 -2
  43. package/dist/{chunk-OQU65525.js → chunk-24YW7BHC.js} +1 -1
  44. package/dist/{chunk-BZYQHJDM.js → chunk-2KTPIE57.js} +25 -5
  45. package/dist/{chunk-TJ5L2UTE.js → chunk-5K3LATTM.js} +1 -1
  46. package/dist/{chunk-HDNDL6D5.js → chunk-5LDBYOSJ.js} +1 -1
  47. package/dist/{chunk-FDPPZLSQ.js → chunk-5ZWKM7MO.js} +1 -1
  48. package/dist/{chunk-B3IIPTY3.js → chunk-6MB6TMAG.js} +1 -1
  49. package/dist/{chunk-IOVXB6QN.js → chunk-GXTAHCND.js} +1 -1
  50. package/dist/{chunk-FKQCPRKI.js → chunk-MAOIHKFO.js} +1 -1
  51. package/dist/{chunk-ZAF6JH23.js → chunk-MBOW6YXN.js} +19 -1
  52. package/dist/{chunk-A2UZTLRV.js → chunk-MLXKSX3L.js} +1 -1
  53. package/dist/{chunk-7FL3U7Z5.js → chunk-MWGEXHOD.js} +1 -1
  54. package/dist/{chunk-6CV4XG3J.js → chunk-QFDFAWZ6.js} +1 -1
  55. package/dist/{chunk-2VAWP6FI.js → chunk-RAS62JXV.js} +1 -1
  56. package/dist/{chunk-OTZU76DH.js → chunk-XAF3CYCW.js} +1 -1
  57. package/dist/{chunk-T6GMRZWC.js → chunk-XTYQCTDD.js} +1 -1
  58. package/dist/{chunk-TIXVEPS2.js → chunk-YN7OI5ZV.js} +1 -1
  59. package/dist/cli/neuroverse.cjs +229 -93
  60. package/dist/cli/neuroverse.js +16 -12
  61. package/dist/cli/plan.cjs +18 -0
  62. package/dist/cli/radiant.cjs +42 -4
  63. package/dist/cli/radiant.js +3 -3
  64. package/dist/cli/run.cjs +18 -0
  65. package/dist/cli/run.js +4 -4
  66. package/dist/{decision-flow-IJPNMVQK.js → decision-flow-5VI5YG6A.js} +2 -2
  67. package/dist/{demo-6W3YXLAX.js → demo-GYX6CYHC.js} +2 -2
  68. package/dist/engine/guard-engine.cjs +19 -1
  69. package/dist/engine/guard-engine.d.cts +21 -1
  70. package/dist/engine/guard-engine.d.ts +21 -1
  71. package/dist/engine/guard-engine.js +1 -1
  72. package/dist/{equity-penalties-CCO3GVHS.js → equity-penalties-NOM46NEO.js} +2 -2
  73. package/dist/{guard-IHJEKHL2.js → guard-PQ3SYV4Y.js} +3 -3
  74. package/dist/{guard-contract-ddiIPlOg.d.cts → guard-contract-Oznf-Kgq.d.cts} +32 -0
  75. package/dist/{guard-contract-q6HJAq3Q.d.ts → guard-contract-w_i_6gh-.d.ts} +32 -0
  76. package/dist/{impact-WIAM66IH.js → impact-LDJLTVRU.js} +3 -3
  77. package/dist/index.cjs +62 -1
  78. package/dist/index.d.cts +4 -3
  79. package/dist/index.d.ts +4 -3
  80. package/dist/index.js +49 -8
  81. package/dist/{mcp-server-CKYBHXWK.js → mcp-server-W3MWSKD7.js} +2 -2
  82. package/dist/{playground-3TTBN7XD.js → playground-SSZRNUAF.js} +1 -1
  83. package/dist/radiant/index.cjs +450 -5
  84. package/dist/radiant/index.d.cts +151 -1
  85. package/dist/radiant/index.d.ts +151 -1
  86. package/dist/radiant/index.js +405 -2
  87. package/dist/{redteam-W644UMWN.js → redteam-KCULS7EW.js} +1 -1
  88. package/dist/{server-EI5JCIBU.js → server-EGRGGSM2.js} +2 -2
  89. package/dist/{session-FMAROEIE.js → session-PZLTL22G.js} +2 -2
  90. package/dist/{shared-PpalGKxc.d.cts → shared-BC8mOpt0.d.cts} +1 -1
  91. package/dist/{shared-DAzdfWtU.d.ts → shared-CP63gNNW.d.ts} +1 -1
  92. package/dist/{test-XDB2DH3L.js → test-LIHGWHBA.js} +1 -1
  93. package/dist/{trace-2YDNAXMK.js → trace-DC3D7XPD.js} +2 -2
  94. package/package.json +1 -1
  95. /package/dist/{doctor-XEMLO6UA.js → doctor-SIWQGTAO.js} +0 -0
@@ -56,16 +56,20 @@ __export(radiant_exports, {
56
56
  fetchDiscordActivity: () => fetchDiscordActivity,
57
57
  fetchGitHubActivity: () => fetchGitHubActivity,
58
58
  fetchGitHubOrgActivity: () => fetchGitHubOrgActivity,
59
+ fetchGoogleWorkspaceActivity: () => fetchGoogleWorkspaceActivity,
59
60
  fetchLinearActivity: () => fetchLinearActivity,
60
61
  fetchNotionActivity: () => fetchNotionActivity,
62
+ fetchSalesforceActivity: () => fetchSalesforceActivity,
61
63
  fetchSlackActivity: () => fetchSlackActivity,
62
64
  filterEventsByUser: () => filterEventsByUser,
63
65
  formatActiveWorlds: () => formatActiveWorlds,
64
66
  formatDiscordSignalsForPrompt: () => formatDiscordSignalsForPrompt,
65
67
  formatExocortexForPrompt: () => formatExocortexForPrompt,
68
+ formatGoogleWorkspaceSignalsForPrompt: () => formatGoogleWorkspaceSignalsForPrompt,
66
69
  formatLinearSignalsForPrompt: () => formatLinearSignalsForPrompt,
67
70
  formatNotionSignalsForPrompt: () => formatNotionSignalsForPrompt,
68
71
  formatPriorReadsForPrompt: () => formatPriorReadsForPrompt,
72
+ formatSalesforceSignalsForPrompt: () => formatSalesforceSignalsForPrompt,
69
73
  formatScope: () => formatScope,
70
74
  formatSlackSignalsForPrompt: () => formatSlackSignalsForPrompt,
71
75
  formatTeamExocorticesForPrompt: () => formatTeamExocorticesForPrompt,
@@ -2296,6 +2300,405 @@ async function fetchLinearGraphQL(apiKey, query, variables) {
2296
2300
  return json.data;
2297
2301
  }
2298
2302
 
2303
+ // src/radiant/adapters/google-workspace.ts
2304
+ async function fetchGoogleWorkspaceActivity(options) {
2305
+ const windowDays = options.windowDays ?? 14;
2306
+ const maxEmails = options.maxEmails ?? 100;
2307
+ const maxEvents = options.maxEvents ?? 100;
2308
+ const leaderEmail = options.leaderEmail?.toLowerCase();
2309
+ const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
2310
+ const [emailEvents, emailSignals] = await fetchGmailSent(
2311
+ options.accessToken,
2312
+ since,
2313
+ maxEmails,
2314
+ leaderEmail
2315
+ );
2316
+ const [calendarEvents, calendarSignals] = await fetchCalendarEvents(
2317
+ options.accessToken,
2318
+ since,
2319
+ maxEvents,
2320
+ leaderEmail
2321
+ );
2322
+ const events = [...emailEvents, ...calendarEvents].sort(
2323
+ (a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)
2324
+ );
2325
+ return {
2326
+ events,
2327
+ signals: {
2328
+ ...emailSignals,
2329
+ ...calendarSignals
2330
+ }
2331
+ };
2332
+ }
2333
+ function formatGoogleWorkspaceSignalsForPrompt(signals) {
2334
+ if (signals.emailsSent === 0 && signals.meetingsHeld === 0) return "";
2335
+ const lines = [
2336
+ "## Google Workspace Activity (external coordination + meeting load)",
2337
+ ""
2338
+ ];
2339
+ if (signals.emailsSent > 0) {
2340
+ lines.push(
2341
+ `${signals.emailsSent} emails sent in window, to ${signals.uniqueRecipients} unique recipients.`
2342
+ );
2343
+ if (signals.topRecipients.length > 0) {
2344
+ lines.push(`Most-emailed: ${signals.topRecipients.slice(0, 5).join(", ")}.`);
2345
+ }
2346
+ }
2347
+ if (signals.meetingsHeld > 0) {
2348
+ const hours = Math.round(signals.totalMeetingMinutes / 60 * 10) / 10;
2349
+ lines.push(
2350
+ `${signals.meetingsHeld} meetings held (${signals.meetingsOrganized} organized by the leader), ${hours}h total.`
2351
+ );
2352
+ if (signals.avgMeetingAttendees !== null) {
2353
+ lines.push(
2354
+ `Average ${signals.avgMeetingAttendees} attendees per meeting, ${signals.uniqueAttendees} unique attendees total.`
2355
+ );
2356
+ }
2357
+ }
2358
+ lines.push("");
2359
+ lines.push(
2360
+ "Gmail sent volume + Calendar meeting load reveal a leader's external coordination shape."
2361
+ );
2362
+ lines.push(
2363
+ "Compare against shipped work (GitHub, Linear) to find the stated-strategy-vs-actual-time gap."
2364
+ );
2365
+ return lines.join("\n");
2366
+ }
2367
+ async function fetchGmailSent(token, since, maxEmails, leaderEmail) {
2368
+ const sinceUnix = Math.floor(since.getTime() / 1e3);
2369
+ const listUrl = new URL("https://gmail.googleapis.com/gmail/v1/users/me/messages");
2370
+ listUrl.searchParams.set("q", `in:sent after:${sinceUnix}`);
2371
+ listUrl.searchParams.set("maxResults", String(Math.min(maxEmails, 100)));
2372
+ const listRes = await fetch(listUrl.toString(), {
2373
+ headers: { Authorization: `Bearer ${token}` }
2374
+ });
2375
+ if (!listRes.ok) {
2376
+ throw new Error(`Gmail list failed ${listRes.status}: ${(await listRes.text()).slice(0, 200)}`);
2377
+ }
2378
+ const listJson = await listRes.json();
2379
+ const ids = (listJson.messages ?? []).slice(0, maxEmails);
2380
+ const events = [];
2381
+ const recipientCounts = /* @__PURE__ */ new Map();
2382
+ const PARALLEL = 5;
2383
+ for (let i = 0; i < ids.length; i += PARALLEL) {
2384
+ const chunk = ids.slice(i, i + PARALLEL);
2385
+ const results = await Promise.all(
2386
+ chunk.map(
2387
+ (m) => fetch(
2388
+ `https://gmail.googleapis.com/gmail/v1/users/me/messages/${m.id}?format=metadata&metadataHeaders=From&metadataHeaders=To&metadataHeaders=Subject&metadataHeaders=Date`,
2389
+ { headers: { Authorization: `Bearer ${token}` } }
2390
+ ).then((r) => r.ok ? r.json() : null).catch(() => null)
2391
+ )
2392
+ );
2393
+ for (const msg of results) {
2394
+ if (!msg) continue;
2395
+ const headers = msg.payload?.headers || [];
2396
+ const header = (n) => headers.find((h) => h.name.toLowerCase() === n.toLowerCase())?.value ?? "";
2397
+ const subject = header("Subject") || "(no subject)";
2398
+ const to = header("To");
2399
+ const dateHdr = header("Date");
2400
+ const timestamp = dateHdr ? new Date(dateHdr).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
2401
+ const snippet = msg.snippet ?? "";
2402
+ const recipients = parseAddressList(to);
2403
+ for (const r of recipients) {
2404
+ recipientCounts.set(r, (recipientCounts.get(r) ?? 0) + 1);
2405
+ }
2406
+ events.push({
2407
+ id: `gmail-${msg.id}`,
2408
+ timestamp,
2409
+ actor: {
2410
+ id: leaderEmail ?? "leader",
2411
+ kind: "human",
2412
+ name: leaderEmail ?? "Leader"
2413
+ },
2414
+ kind: "email_sent",
2415
+ content: `${subject} \u2014 ${snippet.slice(0, 200)}`,
2416
+ metadata: {
2417
+ to: recipients.slice(0, 5),
2418
+ subject
2419
+ }
2420
+ });
2421
+ }
2422
+ }
2423
+ const topRecipients = [...recipientCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([addr]) => addr);
2424
+ return [
2425
+ events,
2426
+ {
2427
+ emailsSent: events.length,
2428
+ uniqueRecipients: recipientCounts.size,
2429
+ topRecipients
2430
+ }
2431
+ ];
2432
+ }
2433
+ function parseAddressList(raw) {
2434
+ if (!raw) return [];
2435
+ return raw.split(",").map((a) => {
2436
+ const match = a.match(/<([^>]+)>/);
2437
+ const addr = (match ? match[1] : a).trim().toLowerCase();
2438
+ return addr;
2439
+ }).filter((a) => a.includes("@") && a.length < 100);
2440
+ }
2441
+ async function fetchCalendarEvents(token, since, maxEvents, leaderEmail) {
2442
+ const timeMin = since.toISOString();
2443
+ const timeMax = (/* @__PURE__ */ new Date()).toISOString();
2444
+ const url = new URL("https://www.googleapis.com/calendar/v3/calendars/primary/events");
2445
+ url.searchParams.set("timeMin", timeMin);
2446
+ url.searchParams.set("timeMax", timeMax);
2447
+ url.searchParams.set("singleEvents", "true");
2448
+ url.searchParams.set("orderBy", "startTime");
2449
+ url.searchParams.set("maxResults", String(Math.min(maxEvents, 250)));
2450
+ const res = await fetch(url.toString(), {
2451
+ headers: { Authorization: `Bearer ${token}` }
2452
+ });
2453
+ if (!res.ok) {
2454
+ throw new Error(`Calendar list failed ${res.status}: ${(await res.text()).slice(0, 200)}`);
2455
+ }
2456
+ const json = await res.json();
2457
+ const events = [];
2458
+ const attendeeSet = /* @__PURE__ */ new Set();
2459
+ let totalMinutes = 0;
2460
+ let meetingsOrganized = 0;
2461
+ const attendeeCounts = [];
2462
+ for (const ev of json.items ?? []) {
2463
+ if (ev.status === "cancelled") continue;
2464
+ const start = ev.start?.dateTime || ev.start?.date;
2465
+ const end = ev.end?.dateTime || ev.end?.date;
2466
+ if (!start) continue;
2467
+ const startMs = new Date(start).getTime();
2468
+ const endMs = end ? new Date(end).getTime() : startMs;
2469
+ const minutes = Math.max(0, Math.round((endMs - startMs) / 6e4));
2470
+ totalMinutes += minutes;
2471
+ const attendees = (ev.attendees ?? []).map((a) => a.email?.toLowerCase()).filter((e) => !!e && e.includes("@"));
2472
+ for (const a of attendees) attendeeSet.add(a);
2473
+ attendeeCounts.push(attendees.length);
2474
+ const organizedByLeader = leaderEmail && ev.organizer?.email?.toLowerCase() === leaderEmail;
2475
+ if (organizedByLeader) meetingsOrganized++;
2476
+ events.push({
2477
+ id: `gcal-${ev.id}`,
2478
+ timestamp: start,
2479
+ actor: {
2480
+ id: leaderEmail ?? "leader",
2481
+ kind: "human",
2482
+ name: leaderEmail ?? "Leader"
2483
+ },
2484
+ kind: organizedByLeader ? "meeting_organized" : "meeting_attended",
2485
+ content: `${ev.summary ?? "(no title)"} \u2014 ${minutes}min, ${attendees.length} attendees`,
2486
+ metadata: {
2487
+ attendees: attendees.slice(0, 10),
2488
+ minutes,
2489
+ organizer: ev.organizer?.email
2490
+ }
2491
+ });
2492
+ }
2493
+ const avgAttendees = attendeeCounts.length > 0 ? Math.round(
2494
+ attendeeCounts.reduce((a, b) => a + b, 0) / attendeeCounts.length
2495
+ ) : null;
2496
+ return [
2497
+ events,
2498
+ {
2499
+ meetingsHeld: events.length,
2500
+ meetingsOrganized,
2501
+ uniqueAttendees: attendeeSet.size,
2502
+ totalMeetingMinutes: totalMinutes,
2503
+ avgMeetingAttendees: avgAttendees
2504
+ }
2505
+ ];
2506
+ }
2507
+
2508
+ // src/radiant/adapters/salesforce.ts
2509
+ async function fetchSalesforceActivity(options) {
2510
+ const windowDays = options.windowDays ?? 14;
2511
+ const maxRecords = Math.min(options.maxRecords ?? 200, 200);
2512
+ const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
2513
+ const sinceSoql = since.toISOString();
2514
+ const events = [];
2515
+ const signals = {
2516
+ opportunitiesMoved: 0,
2517
+ stageTransitions: 0,
2518
+ amountChanges: 0,
2519
+ closedWon: 0,
2520
+ closedLost: 0,
2521
+ tasksLogged: 0,
2522
+ callsLogged: 0,
2523
+ feedPostsByLeader: 0,
2524
+ totalPipelineAmount: 0,
2525
+ topStages: []
2526
+ };
2527
+ const opps = await soqlQuery(
2528
+ options,
2529
+ `SELECT Id, Name, StageName, Amount, CloseDate, IsClosed, IsWon, LastModifiedDate, Owner.Name
2530
+ FROM Opportunity
2531
+ WHERE LastModifiedDate >= ${sinceSoql}
2532
+ ORDER BY LastModifiedDate DESC
2533
+ LIMIT ${maxRecords}`
2534
+ );
2535
+ const stageCounts = /* @__PURE__ */ new Map();
2536
+ for (const opp of opps) {
2537
+ signals.opportunitiesMoved++;
2538
+ signals.totalPipelineAmount += opp.Amount ?? 0;
2539
+ stageCounts.set(opp.StageName, (stageCounts.get(opp.StageName) ?? 0) + 1);
2540
+ if (opp.IsClosed && opp.IsWon) signals.closedWon++;
2541
+ if (opp.IsClosed && !opp.IsWon) signals.closedLost++;
2542
+ events.push({
2543
+ id: `sf-opp-${opp.Id}`,
2544
+ timestamp: opp.LastModifiedDate,
2545
+ actor: {
2546
+ id: opp.Owner?.Name ?? "unknown",
2547
+ kind: "human",
2548
+ name: opp.Owner?.Name ?? "unknown"
2549
+ },
2550
+ kind: opp.IsClosed ? opp.IsWon ? "deal_won" : "deal_lost" : "deal_updated",
2551
+ content: `${opp.Name} \u2014 ${opp.StageName}${opp.Amount ? ` \xB7 $${Math.round(opp.Amount).toLocaleString()}` : ""} \xB7 close ${opp.CloseDate}`,
2552
+ metadata: {
2553
+ opportunityId: opp.Id,
2554
+ stage: opp.StageName,
2555
+ amount: opp.Amount,
2556
+ closeDate: opp.CloseDate
2557
+ }
2558
+ });
2559
+ }
2560
+ signals.topStages = [...stageCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([stage, count]) => ({ stage, count }));
2561
+ const history = await soqlQuery(
2562
+ options,
2563
+ `SELECT Id, OpportunityId, Field, OldValue, NewValue, CreatedDate, CreatedBy.Name
2564
+ FROM OpportunityFieldHistory
2565
+ WHERE CreatedDate >= ${sinceSoql} AND Field IN ('StageName', 'Amount', 'CloseDate')
2566
+ ORDER BY CreatedDate DESC
2567
+ LIMIT ${maxRecords}`
2568
+ ).catch(() => []);
2569
+ for (const h of history) {
2570
+ if (h.Field === "StageName") signals.stageTransitions++;
2571
+ if (h.Field === "Amount") signals.amountChanges++;
2572
+ events.push({
2573
+ id: `sf-hist-${h.Id}`,
2574
+ timestamp: h.CreatedDate,
2575
+ actor: {
2576
+ id: h.CreatedBy?.Name ?? "unknown",
2577
+ kind: "human",
2578
+ name: h.CreatedBy?.Name ?? "unknown"
2579
+ },
2580
+ kind: `deal_${h.Field.toLowerCase()}_changed`,
2581
+ content: `${h.Field}: ${String(h.OldValue)} \u2192 ${String(h.NewValue)}`,
2582
+ metadata: {
2583
+ opportunityId: h.OpportunityId,
2584
+ field: h.Field
2585
+ }
2586
+ });
2587
+ }
2588
+ const tasks = await soqlQuery(
2589
+ options,
2590
+ `SELECT Id, Subject, Status, Type, CreatedDate, Owner.Name
2591
+ FROM Task
2592
+ WHERE CreatedDate >= ${sinceSoql}
2593
+ ORDER BY CreatedDate DESC
2594
+ LIMIT ${maxRecords}`
2595
+ ).catch(() => []);
2596
+ for (const t of tasks) {
2597
+ signals.tasksLogged++;
2598
+ if (t.Type === "Call" || (t.Subject || "").toLowerCase().includes("call")) {
2599
+ signals.callsLogged++;
2600
+ }
2601
+ events.push({
2602
+ id: `sf-task-${t.Id}`,
2603
+ timestamp: t.CreatedDate,
2604
+ actor: {
2605
+ id: t.Owner?.Name ?? "unknown",
2606
+ kind: "human",
2607
+ name: t.Owner?.Name ?? "unknown"
2608
+ },
2609
+ kind: t.Type === "Call" ? "call_logged" : "task_logged",
2610
+ content: `${t.Subject} \u2014 ${t.Status}`,
2611
+ metadata: { taskId: t.Id, type: t.Type, status: t.Status }
2612
+ });
2613
+ }
2614
+ if (options.leaderName) {
2615
+ const feed = await soqlQuery(
2616
+ options,
2617
+ `SELECT Id, Body, CreatedDate, CreatedBy.Name, ParentId
2618
+ FROM FeedItem
2619
+ WHERE CreatedDate >= ${sinceSoql} AND CreatedBy.Name = '${escapeSoql(options.leaderName)}'
2620
+ ORDER BY CreatedDate DESC
2621
+ LIMIT ${Math.min(maxRecords, 50)}`
2622
+ ).catch(() => []);
2623
+ for (const f of feed) {
2624
+ signals.feedPostsByLeader++;
2625
+ events.push({
2626
+ id: `sf-feed-${f.Id}`,
2627
+ timestamp: f.CreatedDate,
2628
+ actor: {
2629
+ id: f.CreatedBy?.Name ?? "unknown",
2630
+ kind: "human",
2631
+ name: f.CreatedBy?.Name ?? "unknown"
2632
+ },
2633
+ kind: "feed_post",
2634
+ content: (f.Body || "").slice(0, 280),
2635
+ metadata: { feedId: f.Id, parent: f.ParentId }
2636
+ });
2637
+ }
2638
+ }
2639
+ events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
2640
+ return { events, signals };
2641
+ }
2642
+ function formatSalesforceSignalsForPrompt(signals) {
2643
+ if (signals.opportunitiesMoved === 0 && signals.tasksLogged === 0 && signals.stageTransitions === 0) {
2644
+ return "";
2645
+ }
2646
+ const lines = [
2647
+ "## Salesforce Activity (stated pipeline vs observed motion)",
2648
+ ""
2649
+ ];
2650
+ if (signals.opportunitiesMoved > 0) {
2651
+ const pipelineM = Math.round(signals.totalPipelineAmount / 1e4) / 100;
2652
+ lines.push(
2653
+ `${signals.opportunitiesMoved} opportunities touched in window ($${pipelineM}M total pipeline represented).`
2654
+ );
2655
+ lines.push(
2656
+ `${signals.stageTransitions} stage changes, ${signals.amountChanges} amount changes.`
2657
+ );
2658
+ if (signals.closedWon + signals.closedLost > 0) {
2659
+ lines.push(`${signals.closedWon} closed won, ${signals.closedLost} closed lost.`);
2660
+ }
2661
+ if (signals.topStages.length > 0) {
2662
+ lines.push(
2663
+ `Most active stages: ${signals.topStages.map((s) => `${s.stage} (${s.count})`).join(", ")}.`
2664
+ );
2665
+ }
2666
+ }
2667
+ if (signals.tasksLogged > 0) {
2668
+ lines.push(
2669
+ `${signals.tasksLogged} tasks logged (${signals.callsLogged} calls).`
2670
+ );
2671
+ }
2672
+ if (signals.feedPostsByLeader > 0) {
2673
+ lines.push(`${signals.feedPostsByLeader} feed posts by the leader.`);
2674
+ }
2675
+ lines.push("");
2676
+ lines.push(
2677
+ "Salesforce shows what the team said would happen (stages, forecast) vs. what is actually happening (movement, activity, close)."
2678
+ );
2679
+ lines.push(
2680
+ "Compare stage transitions against stated strategy \u2014 are the deals the leader said would close actually moving, or is the pipeline drifting?"
2681
+ );
2682
+ return lines.join("\n");
2683
+ }
2684
+ async function soqlQuery(opts, query) {
2685
+ const url = new URL(`${opts.instanceUrl}/services/data/v59.0/query`);
2686
+ url.searchParams.set("q", query);
2687
+ const res = await fetch(url.toString(), {
2688
+ headers: { Authorization: `Bearer ${opts.accessToken}` }
2689
+ });
2690
+ if (!res.ok) {
2691
+ throw new Error(
2692
+ `Salesforce SOQL ${res.status}: ${(await res.text()).slice(0, 200)}`
2693
+ );
2694
+ }
2695
+ const json = await res.json();
2696
+ return json.records ?? [];
2697
+ }
2698
+ function escapeSoql(raw) {
2699
+ return raw.replace(/['\\]/g, "");
2700
+ }
2701
+
2299
2702
  // src/radiant/core/vocabulary.ts
2300
2703
  function extractDeclaredVocabulary(worldmodelContent) {
2301
2704
  const aligned = extractSection(worldmodelContent, "Aligned Behaviors").map(
@@ -3560,8 +3963,26 @@ function isExternalScope(scope) {
3560
3963
  ];
3561
3964
  return !internalPatterns.some((p) => p.test(scope));
3562
3965
  }
3563
- var MAX_INPUT_LENGTH = 1e5;
3564
3966
  function evaluateGuard(event, world, options = {}) {
3967
+ const verdict = evaluateGuardCore(event, world, options);
3968
+ return options.mode === "observe" ? toShadowVerdict(verdict) : verdict;
3969
+ }
3970
+ function toShadowVerdict(verdict) {
3971
+ if (verdict.status === "ALLOW") return verdict;
3972
+ return {
3973
+ ...verdict,
3974
+ status: "ALLOW",
3975
+ shadowStatus: verdict.status,
3976
+ shadowReason: verdict.reason,
3977
+ // Preserve the original reason as shadowReason and wipe the
3978
+ // top-level reason so callers that display `reason` for BLOCK/PAUSE
3979
+ // don't accidentally surface an enforcement message.
3980
+ reason: void 0,
3981
+ warning: verdict.reason ? `Observe mode: would have ${verdict.status.toLowerCase()} \u2014 ${verdict.reason}` : `Observe mode: would have ${verdict.status.toLowerCase()}`
3982
+ };
3983
+ }
3984
+ var MAX_INPUT_LENGTH = 1e5;
3985
+ function evaluateGuardCore(event, world, options = {}) {
3565
3986
  const startTime = performance.now();
3566
3987
  const level = options.level ?? "standard";
3567
3988
  const includeTrace = options.trace ?? false;
@@ -4451,6 +4872,7 @@ async function auditGovernance(events, worldPath) {
4451
4872
  return emptyAudit(events.length, "Could not load compiled worldmodel for governance audit.");
4452
4873
  }
4453
4874
  const verdicts = [];
4875
+ const crossings = [];
4454
4876
  for (const ce of events) {
4455
4877
  const intent = ce.event.content?.slice(0, 500) || ce.event.kind || "activity";
4456
4878
  const scope = ce.event.metadata?.scope || void 0;
@@ -4461,16 +4883,32 @@ async function auditGovernance(events, worldPath) {
4461
4883
  scope,
4462
4884
  actionCategory: mapKindToCategory(ce.event.kind)
4463
4885
  },
4464
- world
4886
+ world,
4887
+ { mode: "observe" }
4465
4888
  );
4889
+ const shadow = result.shadowStatus ?? "ALLOW";
4466
4890
  verdicts.push({
4467
4891
  eventId: ce.event.id,
4468
4892
  domain: ce.domain,
4469
- status: result.status,
4470
- reason: result.reason,
4893
+ status: shadow,
4894
+ reason: result.shadowReason,
4471
4895
  ruleId: result.ruleId,
4472
4896
  warning: result.warning
4473
4897
  });
4898
+ if (shadow !== "ALLOW") {
4899
+ crossings.push({
4900
+ eventId: ce.event.id,
4901
+ timestamp: ce.event.timestamp,
4902
+ kind: ce.event.kind,
4903
+ actorId: ce.event.actor.id,
4904
+ shadowStatus: shadow,
4905
+ shadowReason: result.shadowReason,
4906
+ ruleId: result.ruleId,
4907
+ excerpt: intent.length > 280 ? intent.slice(0, 279) + "\u2026" : intent,
4908
+ wouldHaveBlocked: true,
4909
+ verdict: result
4910
+ });
4911
+ }
4474
4912
  } catch {
4475
4913
  verdicts.push({
4476
4914
  eventId: ce.event.id,
@@ -4489,6 +4927,7 @@ async function auditGovernance(events, worldPath) {
4489
4927
  human,
4490
4928
  cyber,
4491
4929
  joint,
4930
+ crossings,
4492
4931
  summary
4493
4932
  };
4494
4933
  }
@@ -4544,6 +4983,7 @@ function emptyAudit(total, reason) {
4544
4983
  human: { allow: 0, modify: 0, block: 0, details: [] },
4545
4984
  cyber: { allow: 0, modify: 0, block: 0, details: [] },
4546
4985
  joint: { allow: 0, modify: 0, block: 0, details: [] },
4986
+ crossings: [],
4547
4987
  summary: reason
4548
4988
  };
4549
4989
  }
@@ -4926,7 +5366,8 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
4926
5366
  scores,
4927
5367
  eventCount: events.length,
4928
5368
  activeAdapters,
4929
- worldStack
5369
+ worldStack,
5370
+ governance
4930
5371
  };
4931
5372
  }
4932
5373
  function filterEventsByUser(events, username) {
@@ -5011,16 +5452,20 @@ var RADIANT_PACKAGE_VERSION = "0.0.0";
5011
5452
  fetchDiscordActivity,
5012
5453
  fetchGitHubActivity,
5013
5454
  fetchGitHubOrgActivity,
5455
+ fetchGoogleWorkspaceActivity,
5014
5456
  fetchLinearActivity,
5015
5457
  fetchNotionActivity,
5458
+ fetchSalesforceActivity,
5016
5459
  fetchSlackActivity,
5017
5460
  filterEventsByUser,
5018
5461
  formatActiveWorlds,
5019
5462
  formatDiscordSignalsForPrompt,
5020
5463
  formatExocortexForPrompt,
5464
+ formatGoogleWorkspaceSignalsForPrompt,
5021
5465
  formatLinearSignalsForPrompt,
5022
5466
  formatNotionSignalsForPrompt,
5023
5467
  formatPriorReadsForPrompt,
5468
+ formatSalesforceSignalsForPrompt,
5024
5469
  formatScope,
5025
5470
  formatSlackSignalsForPrompt,
5026
5471
  formatTeamExocorticesForPrompt,