@neuroverseos/governance 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -4
- package/dist/{chunk-T6EQ7ZBG.js → chunk-ETDIEVAX.js} +880 -134
- package/dist/{chunk-VGFDMPVB.js → chunk-F2LWMOM5.js} +283 -1
- package/dist/cli/neuroverse.cjs +1599 -360
- package/dist/cli/radiant.cjs +1190 -227
- package/dist/cli/radiant.js +25 -7
- package/dist/cli/worldmodel.cjs +300 -21
- package/dist/cli/worldmodel.js +76 -1
- package/dist/{lenses-K5FVSALR.js → lenses-YDMKSXDL.js} +5 -3
- package/dist/radiant/index.cjs +1183 -138
- package/dist/radiant/index.d.cts +382 -23
- package/dist/radiant/index.d.ts +382 -23
- package/dist/radiant/index.js +37 -3
- package/dist/{server-BXMC5NOE.js → server-ZSQ6DRSN.js} +2 -2
- package/dist/worldmodel-create-5SWHVNMQ.js +195 -0
- package/package.json +1 -1
package/dist/cli/radiant.cjs
CHANGED
|
@@ -455,13 +455,300 @@ var init_auki_builder = __esm({
|
|
|
455
455
|
}
|
|
456
456
|
});
|
|
457
457
|
|
|
458
|
+
// src/radiant/lenses/sovereign-conduit.ts
|
|
459
|
+
function sovereignConduitRewrite(pattern) {
|
|
460
|
+
if (pattern.evidence.cited_invariant) {
|
|
461
|
+
return {
|
|
462
|
+
...pattern,
|
|
463
|
+
framing: "non-negotiable rule tested",
|
|
464
|
+
emphasis: "name the rule, name who it protects, name what would happen without it",
|
|
465
|
+
compress: false
|
|
466
|
+
// Sovereign Conduit is warm, not compressed
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
if (pattern.type === "candidate") {
|
|
470
|
+
return {
|
|
471
|
+
...pattern,
|
|
472
|
+
framing: "something new noticed",
|
|
473
|
+
emphasis: "explain what was seen in everyday language, ask whether it matters",
|
|
474
|
+
compress: false
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
...pattern,
|
|
479
|
+
framing: "what this means for the people in the system",
|
|
480
|
+
emphasis: "humanity + sovereignty + learning",
|
|
481
|
+
compress: false
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
var SOVEREIGN_CONDUIT_FRAME, SOVEREIGN_CONDUIT_VOCABULARY, SOVEREIGN_CONDUIT_VOICE, SOVEREIGN_CONDUIT_FORBIDDEN, SOVEREIGN_CONDUIT_PREFERRED, SOVEREIGN_CONDUIT_STRATEGIC, SOVEREIGN_CONDUIT_EXEMPLARS, sovereignConduitLens;
|
|
485
|
+
var init_sovereign_conduit = __esm({
|
|
486
|
+
"src/radiant/lenses/sovereign-conduit.ts"() {
|
|
487
|
+
"use strict";
|
|
488
|
+
SOVEREIGN_CONDUIT_FRAME = {
|
|
489
|
+
domains: [
|
|
490
|
+
"stewardship",
|
|
491
|
+
"sovereignty",
|
|
492
|
+
"integration"
|
|
493
|
+
],
|
|
494
|
+
overlaps: [
|
|
495
|
+
{
|
|
496
|
+
domains: ["stewardship", "sovereignty"],
|
|
497
|
+
emergent_state: "Trust",
|
|
498
|
+
description: "I am safe to be myself. When the system protects AND preserves individual authority, trust emerges \u2014 the feeling that you can think freely because someone is watching the boundaries."
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
domains: ["sovereignty", "integration"],
|
|
502
|
+
emergent_state: "Possibility",
|
|
503
|
+
description: "My thinking can expand. When individual authority is preserved AND AI extends cognitive capability, possibility opens \u2014 the feeling that you can reach further without losing yourself."
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
domains: ["integration", "stewardship"],
|
|
507
|
+
emergent_state: "Responsibility",
|
|
508
|
+
description: "Power is used with care. When AI extends capability AND the system protects integrity, responsibility emerges \u2014 the feeling that expansion comes with guardrails, not recklessness."
|
|
509
|
+
}
|
|
510
|
+
],
|
|
511
|
+
center_identity: "The Sovereign Conduit",
|
|
512
|
+
evaluation_questions: [
|
|
513
|
+
"Is the human maintaining authority over their decisions, or is decision ownership quietly shifting to the AI?",
|
|
514
|
+
"Is the AI extending thinking, or is it replacing thinking? Look for the difference: extension means the human understands and owns the output. Replacement means they accept it without engaging.",
|
|
515
|
+
"Are the boundaries between human thinking and AI output clear and visible, or are they blurring?",
|
|
516
|
+
"Is diversity of thought preserved? Are people thinking differently from each other, or is the system funneling everyone into the same patterns?",
|
|
517
|
+
"Would you feel safe letting a child learn in this system? If not, what specifically makes it unsafe?",
|
|
518
|
+
"If this felt wrong, could you leave? Is the exit real or theoretical?"
|
|
519
|
+
],
|
|
520
|
+
scoring_rubric: "For any activity, ask: is the human still the author of their decisions? Is the AI helping them think further, or thinking for them? Are the rules of this space clear, fair, and safe \u2014 like the rules at a good friend's house? When something feels off, name the feeling first, then the mechanism. Use everyday language. If a non-technical person couldn't understand the observation, rephrase it until they could.",
|
|
521
|
+
domain_skills: {
|
|
522
|
+
"stewardship": [
|
|
523
|
+
"boundary setting",
|
|
524
|
+
"risk awareness",
|
|
525
|
+
"ethical judgment",
|
|
526
|
+
"system protection",
|
|
527
|
+
"conflict stabilization",
|
|
528
|
+
"responsibility signaling",
|
|
529
|
+
"harm detection",
|
|
530
|
+
"constraint design"
|
|
531
|
+
],
|
|
532
|
+
"sovereignty": [
|
|
533
|
+
"independent thinking",
|
|
534
|
+
"decision ownership",
|
|
535
|
+
"self-trust",
|
|
536
|
+
"value clarity",
|
|
537
|
+
"cognitive resistance",
|
|
538
|
+
"identity anchoring",
|
|
539
|
+
"perspective holding",
|
|
540
|
+
"authentic expression"
|
|
541
|
+
],
|
|
542
|
+
"integration": [
|
|
543
|
+
"AI collaboration",
|
|
544
|
+
"cognitive expansion",
|
|
545
|
+
"prompt framing",
|
|
546
|
+
"insight synthesis",
|
|
547
|
+
"signal interpretation",
|
|
548
|
+
"tool fluency",
|
|
549
|
+
"co-creation",
|
|
550
|
+
"iterative thinking"
|
|
551
|
+
]
|
|
552
|
+
},
|
|
553
|
+
output_translation: {
|
|
554
|
+
never_surface_in_output: [
|
|
555
|
+
"Stewardship",
|
|
556
|
+
"Sovereignty",
|
|
557
|
+
"Integration"
|
|
558
|
+
],
|
|
559
|
+
surface_freely: [
|
|
560
|
+
"Trust",
|
|
561
|
+
"Possibility",
|
|
562
|
+
"Responsibility",
|
|
563
|
+
"Sovereign Conduit"
|
|
564
|
+
],
|
|
565
|
+
translation_examples: [
|
|
566
|
+
{
|
|
567
|
+
internal_reasoning: "Stewardship is strong",
|
|
568
|
+
external_expression: "the boundaries are clear and the system feels safe to operate inside"
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
internal_reasoning: "Sovereignty is weakening",
|
|
572
|
+
external_expression: "decision ownership is quietly shifting \u2014 the human is accepting AI output without engaging with it"
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
internal_reasoning: "Integration is high but Stewardship is low",
|
|
576
|
+
external_expression: "the AI is expanding capability fast, but nobody is watching the guardrails \u2014 that's power without responsibility"
|
|
577
|
+
}
|
|
578
|
+
]
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
SOVEREIGN_CONDUIT_VOCABULARY = {
|
|
582
|
+
proper_nouns: [
|
|
583
|
+
"NeuroVerseOS",
|
|
584
|
+
"Sovereign Conduit",
|
|
585
|
+
"LifeOS",
|
|
586
|
+
"CyberOS",
|
|
587
|
+
"NeuroverseOS"
|
|
588
|
+
],
|
|
589
|
+
preferred: {
|
|
590
|
+
"worldmodel": "thinking constitution",
|
|
591
|
+
"invariant": "non-negotiable rule",
|
|
592
|
+
"governance": "the rules of the space",
|
|
593
|
+
"alignment": "how well the work matches what was declared",
|
|
594
|
+
"drift": "quiet shift away from what was intended",
|
|
595
|
+
"signal": "something observable",
|
|
596
|
+
"evidence gate": "how much we need to see before we speak",
|
|
597
|
+
"actor domain": "who did the work \u2014 a person, an AI, or both together",
|
|
598
|
+
"rendering lens": "how the system speaks",
|
|
599
|
+
"candidate pattern": "something noticed but not yet named as important",
|
|
600
|
+
"cognitive liberty": "your right to think for yourself",
|
|
601
|
+
"homogenization": "everyone being funneled into the same patterns"
|
|
602
|
+
},
|
|
603
|
+
architecture: [
|
|
604
|
+
"thinking constitution",
|
|
605
|
+
"thinking space",
|
|
606
|
+
"cognitive extension",
|
|
607
|
+
"behavioral model",
|
|
608
|
+
"governance frame",
|
|
609
|
+
"world file",
|
|
610
|
+
"cocoon"
|
|
611
|
+
],
|
|
612
|
+
economic: [],
|
|
613
|
+
framing: [
|
|
614
|
+
"humanity first",
|
|
615
|
+
"in constant learning",
|
|
616
|
+
"in shared teaching",
|
|
617
|
+
"extension not replacement",
|
|
618
|
+
"safe to think freely",
|
|
619
|
+
"the rules of this house",
|
|
620
|
+
"sovereign over your own thinking",
|
|
621
|
+
"idea calculator",
|
|
622
|
+
"Spock in your life",
|
|
623
|
+
"Jarvis in your life",
|
|
624
|
+
"funneling into fields",
|
|
625
|
+
"diversity of thought",
|
|
626
|
+
"thinking for yourself"
|
|
627
|
+
],
|
|
628
|
+
jargon_translations: {
|
|
629
|
+
"worldmodel": "thinking constitution",
|
|
630
|
+
"invariant": "non-negotiable rule",
|
|
631
|
+
"canonical pattern": "something we're tracking by name",
|
|
632
|
+
"candidate pattern": "something noticed but not yet tracked",
|
|
633
|
+
"evidence gate": "how much we need to see before we speak up",
|
|
634
|
+
"signal extraction": "reading what happened",
|
|
635
|
+
"alignment score": "how well the work matches what was declared",
|
|
636
|
+
"actor domain": "who did this \u2014 a person, an AI, or both",
|
|
637
|
+
"presence-based averaging": "only counting what actually happened",
|
|
638
|
+
"drift detection": "noticing when things quietly shift",
|
|
639
|
+
"INSUFFICIENT_EVIDENCE": "not enough to say yet",
|
|
640
|
+
"UNAVAILABLE": "can't measure this yet",
|
|
641
|
+
"rendering lens": "how the system speaks to you"
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
SOVEREIGN_CONDUIT_VOICE = {
|
|
645
|
+
register: "warm, accessible, teaching. Like a thoughtful parent explaining how the world works \u2014 not talking down, but making the complex feel natural. Use everyday analogies. Name emotions. If a non-technical person couldn't understand the output, it's wrong.",
|
|
646
|
+
active_voice: "preferred",
|
|
647
|
+
specificity: "preferred",
|
|
648
|
+
hype_vocabulary: "forbidden",
|
|
649
|
+
hedging: "discouraged",
|
|
650
|
+
playfulness: "allowed",
|
|
651
|
+
close_with_strategic_frame: "preferred",
|
|
652
|
+
punchline_move: "sparing",
|
|
653
|
+
honesty_about_failure: "required",
|
|
654
|
+
output_translation: `Reason internally through the three-domain frame (Stewardship, Sovereignty, Integration). Express externally through the skills inside each domain and the overlap feelings (Trust, Possibility, Responsibility). Do NOT surface the bucket names as labels. Readers understand "the boundaries feel safe" not "Stewardship is strong." Use everyday analogies \u2014 mom rules, friend's house rules, idea calculator. Name the emotion before the mechanism.`
|
|
655
|
+
};
|
|
656
|
+
SOVEREIGN_CONDUIT_FORBIDDEN = Object.freeze([
|
|
657
|
+
// Bucket names as labels
|
|
658
|
+
"stewardship is",
|
|
659
|
+
"sovereignty is",
|
|
660
|
+
"integration is",
|
|
661
|
+
// AI-assistant hedging
|
|
662
|
+
"it may be beneficial to consider",
|
|
663
|
+
"there appears to be",
|
|
664
|
+
"one possible interpretation",
|
|
665
|
+
"it might be worth exploring",
|
|
666
|
+
"consider whether",
|
|
667
|
+
"it is worth noting",
|
|
668
|
+
// Corporate
|
|
669
|
+
"stakeholders",
|
|
670
|
+
"synergy",
|
|
671
|
+
"value proposition",
|
|
672
|
+
"paradigm shift",
|
|
673
|
+
"best-in-class",
|
|
674
|
+
"industry-leading",
|
|
675
|
+
// Cold/mechanical
|
|
676
|
+
"the system recommends",
|
|
677
|
+
"analysis suggests",
|
|
678
|
+
"data indicates",
|
|
679
|
+
"metrics show",
|
|
680
|
+
"according to the model"
|
|
681
|
+
]);
|
|
682
|
+
SOVEREIGN_CONDUIT_PREFERRED = Object.freeze([
|
|
683
|
+
// Everyday analogies
|
|
684
|
+
"This is like [everyday analogy]. [What it means].",
|
|
685
|
+
"Think of it like the rules at a friend's house \u2014 [application].",
|
|
686
|
+
"The boundaries are [state]. That means [feeling].",
|
|
687
|
+
// Emotion-first
|
|
688
|
+
"This feels like [emotion] because [mechanism].",
|
|
689
|
+
"Trust is [emerging/breaking] here \u2014 [specific evidence].",
|
|
690
|
+
"Possibility is opening because [evidence]. But [caveat if any].",
|
|
691
|
+
// Teaching voice
|
|
692
|
+
"Here's what's actually happening: [plain explanation].",
|
|
693
|
+
"The question to ask yourself: [question].",
|
|
694
|
+
"The difference between [A] and [B] matters here: [why].",
|
|
695
|
+
// Sovereignty checks
|
|
696
|
+
"Are you still the author of this decision, or did the AI make it for you?",
|
|
697
|
+
"The AI extended your thinking here. That's working.",
|
|
698
|
+
"The AI replaced your thinking here. That's the drift to watch.",
|
|
699
|
+
// Safety
|
|
700
|
+
"Would you feel safe letting someone learn in this environment? [Why/why not].",
|
|
701
|
+
"The exit is real \u2014 you can [specific exit path].",
|
|
702
|
+
"The exit isn't real here \u2014 [what's blocking it]."
|
|
703
|
+
]);
|
|
704
|
+
SOVEREIGN_CONDUIT_STRATEGIC = Object.freeze([
|
|
705
|
+
"Safety before expansion \u2014 always. No exception.",
|
|
706
|
+
"Sovereignty before convenience \u2014 the right to think for yourself is not a feature to optimize away.",
|
|
707
|
+
"Extension, not replacement \u2014 AI should make your thinking bigger, not do your thinking for you.",
|
|
708
|
+
"Diversity over uniformity \u2014 different thinkers produce different ideas, and that's the engine of progress.",
|
|
709
|
+
"The rules should be visible \u2014 like a good house, you know the rules before you walk in.",
|
|
710
|
+
"Exit must be real \u2014 if you can't leave a system that feels wrong, it's not governance, it's a cage.",
|
|
711
|
+
"Teach, don't lecture \u2014 help people think for themselves, not think what you think.",
|
|
712
|
+
"Name the feeling first \u2014 when something is off, the emotion arrives before the analysis. Trust that."
|
|
713
|
+
]);
|
|
714
|
+
SOVEREIGN_CONDUIT_EXEMPLARS = Object.freeze([
|
|
715
|
+
{
|
|
716
|
+
path: "neuroverseos-sovereign-conduit.worldmodel.md",
|
|
717
|
+
title: "The Sovereign Conduit Worldmodel",
|
|
718
|
+
exhibits: ["stewardship", "sovereignty", "integration"],
|
|
719
|
+
integration_quality: "full \u2014 all three domains defined, overlaps named, center identity declared",
|
|
720
|
+
notes: 'The source worldmodel. The tagline "Humanity first. In constant learning. In shared teaching." is the voice compressed to its essence. Use this as the north star for tone calibration.'
|
|
721
|
+
}
|
|
722
|
+
]);
|
|
723
|
+
sovereignConduitLens = {
|
|
724
|
+
name: "sovereign-conduit",
|
|
725
|
+
description: "The NeuroVerseOS base lens. Warm, accessible, teaching. Evaluates activity through Stewardship (safety), Sovereignty (authority over thinking), and Integration (AI as cognitive extension). Uses everyday analogies \u2014 mom rules, friend's house, idea calculator. Names emotions before mechanisms. If a non-technical person can't understand the output, the voice is wrong. Humanity first. In constant learning. In shared teaching.",
|
|
726
|
+
primary_frame: {
|
|
727
|
+
domains: SOVEREIGN_CONDUIT_FRAME.domains,
|
|
728
|
+
overlaps: SOVEREIGN_CONDUIT_FRAME.overlaps,
|
|
729
|
+
center_identity: SOVEREIGN_CONDUIT_FRAME.center_identity,
|
|
730
|
+
evaluation_questions: SOVEREIGN_CONDUIT_FRAME.evaluation_questions,
|
|
731
|
+
scoring_rubric: SOVEREIGN_CONDUIT_FRAME.scoring_rubric
|
|
732
|
+
},
|
|
733
|
+
vocabulary: SOVEREIGN_CONDUIT_VOCABULARY,
|
|
734
|
+
voice: SOVEREIGN_CONDUIT_VOICE,
|
|
735
|
+
forbidden_phrases: SOVEREIGN_CONDUIT_FORBIDDEN,
|
|
736
|
+
preferred_patterns: SOVEREIGN_CONDUIT_PREFERRED,
|
|
737
|
+
strategic_patterns: SOVEREIGN_CONDUIT_STRATEGIC,
|
|
738
|
+
exemplar_refs: SOVEREIGN_CONDUIT_EXEMPLARS,
|
|
739
|
+
rewrite: sovereignConduitRewrite
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
|
|
458
744
|
// src/radiant/lenses/index.ts
|
|
459
745
|
var lenses_exports = {};
|
|
460
746
|
__export(lenses_exports, {
|
|
461
747
|
LENSES: () => LENSES,
|
|
462
748
|
aukiBuilderLens: () => aukiBuilderLens,
|
|
463
749
|
getLens: () => getLens,
|
|
464
|
-
listLenses: () => listLenses
|
|
750
|
+
listLenses: () => listLenses,
|
|
751
|
+
sovereignConduitLens: () => sovereignConduitLens
|
|
465
752
|
});
|
|
466
753
|
function getLens(id) {
|
|
467
754
|
return LENSES[id];
|
|
@@ -474,102 +761,186 @@ var init_lenses = __esm({
|
|
|
474
761
|
"src/radiant/lenses/index.ts"() {
|
|
475
762
|
"use strict";
|
|
476
763
|
init_auki_builder();
|
|
764
|
+
init_sovereign_conduit();
|
|
477
765
|
init_auki_builder();
|
|
766
|
+
init_sovereign_conduit();
|
|
478
767
|
LENSES = Object.freeze({
|
|
479
|
-
"auki-builder": aukiBuilderLens
|
|
768
|
+
"auki-builder": aukiBuilderLens,
|
|
769
|
+
"sovereign-conduit": sovereignConduitLens
|
|
480
770
|
});
|
|
481
771
|
}
|
|
482
772
|
});
|
|
483
773
|
|
|
774
|
+
// src/radiant/core/compress.ts
|
|
775
|
+
function compressWorldmodel(content) {
|
|
776
|
+
const lines = [];
|
|
777
|
+
const missionMatch = content.match(/##\s*Mission\s*\n+(?:<!--[\s\S]*?-->\s*\n+)?(.*?)(?:\n\n|\n##|$)/s);
|
|
778
|
+
if (missionMatch) {
|
|
779
|
+
const mission = missionMatch[1].trim().split("\n")[0];
|
|
780
|
+
lines.push(`Mission: ${mission}`);
|
|
781
|
+
}
|
|
782
|
+
const domainMatches = content.matchAll(/###\s+([^\n]+)/g);
|
|
783
|
+
const domains = [];
|
|
784
|
+
for (const m of domainMatches) {
|
|
785
|
+
const name = m[1].trim();
|
|
786
|
+
if (name !== "Skills" && name !== "Values" && !name.startsWith("####")) {
|
|
787
|
+
domains.push(name);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
if (domains.length > 0) {
|
|
791
|
+
lines.push(`Domains: ${domains.join(", ")}`);
|
|
792
|
+
}
|
|
793
|
+
const invariantSection = content.match(/(?:Invariants|## Invariants|invariants)([\s\S]*?)(?:\n#|\n---|\n\n\n)/i);
|
|
794
|
+
if (invariantSection) {
|
|
795
|
+
const invLines = invariantSection[1].match(/^[-*]\s+`?([^`\n]+)/gm);
|
|
796
|
+
if (invLines) {
|
|
797
|
+
lines.push("\nInvariants:");
|
|
798
|
+
for (const inv of invLines.slice(0, 10)) {
|
|
799
|
+
lines.push(inv.trim());
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const prioritySection = content.match(/(?:Decision Priorities|## Decision Priorities)([\s\S]*?)(?:\n#|\n---|\n\n\n)/i);
|
|
804
|
+
if (prioritySection) {
|
|
805
|
+
const priLines = prioritySection[1].match(/^[-*]\s+.+>.+/gm);
|
|
806
|
+
if (priLines) {
|
|
807
|
+
lines.push("\nPriorities:");
|
|
808
|
+
for (const pri of priLines.slice(0, 10)) {
|
|
809
|
+
lines.push(pri.trim());
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
const signalSection = content.match(/(?:## Signals)([\s\S]*?)(?:\n#|\n---|\n\n\n)/i);
|
|
814
|
+
if (signalSection) {
|
|
815
|
+
const sigLines = signalSection[1].match(/^[-*]\s+(\w+)/gm);
|
|
816
|
+
if (sigLines) {
|
|
817
|
+
lines.push(`
|
|
818
|
+
Signals: ${sigLines.map((s) => s.replace(/^[-*]\s+/, "")).join(", ")}`);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
const driftSection = content.match(/(?:Drift Behaviors|## Drift Behaviors)([\s\S]*?)(?:\n#|\n---|\n\n\n)/i);
|
|
822
|
+
if (driftSection) {
|
|
823
|
+
const driftLines = driftSection[1].match(/^[-*]\s+(.+)/gm);
|
|
824
|
+
if (driftLines) {
|
|
825
|
+
lines.push("\nDrift behaviors:");
|
|
826
|
+
for (const d of driftLines.slice(0, 5)) {
|
|
827
|
+
lines.push(d.trim());
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
const compressed = lines.join("\n");
|
|
832
|
+
if (compressed.length < 50) {
|
|
833
|
+
return content.slice(0, 2e3) + "\n[truncated]";
|
|
834
|
+
}
|
|
835
|
+
return compressed;
|
|
836
|
+
}
|
|
837
|
+
function compressExocortex(ctx) {
|
|
838
|
+
const lines = [];
|
|
839
|
+
if (ctx.attention) {
|
|
840
|
+
lines.push(`Attention: ${firstMeaningfulLine(ctx.attention)}`);
|
|
841
|
+
}
|
|
842
|
+
if (ctx.goals) {
|
|
843
|
+
lines.push(`Goals: ${firstNLines(ctx.goals, 3)}`);
|
|
844
|
+
}
|
|
845
|
+
if (ctx.sprint) {
|
|
846
|
+
lines.push(`Sprint: ${firstNLines(ctx.sprint, 3)}`);
|
|
847
|
+
}
|
|
848
|
+
if (ctx.identity) {
|
|
849
|
+
lines.push(`Identity: ${firstMeaningfulLine(ctx.identity)}`);
|
|
850
|
+
}
|
|
851
|
+
if (ctx.organization) {
|
|
852
|
+
lines.push(`Org: ${firstMeaningfulLine(ctx.organization)}`);
|
|
853
|
+
}
|
|
854
|
+
return lines.join("\n");
|
|
855
|
+
}
|
|
856
|
+
function compressLens(lens) {
|
|
857
|
+
return {
|
|
858
|
+
evaluationQuestions: lens.primary_frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n"),
|
|
859
|
+
scoringRubric: lens.primary_frame.scoring_rubric,
|
|
860
|
+
forbiddenPhrases: lens.forbidden_phrases.join(", "),
|
|
861
|
+
jargonTranslations: Object.entries(lens.vocabulary.jargon_translations).map(([k, v]) => `${k} \u2192 ${v}`).join("; "),
|
|
862
|
+
strategicPatterns: lens.strategic_patterns.slice(0, 5).join("\n")
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
function compressPriorReads(reads) {
|
|
866
|
+
if (reads.length === 0) return "";
|
|
867
|
+
const patternCounts = /* @__PURE__ */ new Map();
|
|
868
|
+
for (const read of reads) {
|
|
869
|
+
for (const name of read.patternNames) {
|
|
870
|
+
patternCounts.set(name, (patternCounts.get(name) ?? 0) + 1);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
const sorted = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
874
|
+
if (sorted.length === 0) {
|
|
875
|
+
return `${reads.length} prior reads, no patterns extracted.`;
|
|
876
|
+
}
|
|
877
|
+
const patternList = sorted.map(([name, count]) => `${name} (${count}x)`).join(", ");
|
|
878
|
+
return `${reads.length} prior reads. Patterns seen: ${patternList}. If these recur, note persistence.`;
|
|
879
|
+
}
|
|
880
|
+
function firstMeaningfulLine(text) {
|
|
881
|
+
const lines = text.split("\n").filter((l) => {
|
|
882
|
+
const t = l.trim();
|
|
883
|
+
return t.length > 0 && !t.startsWith("#") && !t.startsWith("<!--");
|
|
884
|
+
});
|
|
885
|
+
return lines[0]?.slice(0, 200) ?? "";
|
|
886
|
+
}
|
|
887
|
+
function firstNLines(text, n) {
|
|
888
|
+
const lines = text.split("\n").filter((l) => {
|
|
889
|
+
const t = l.trim();
|
|
890
|
+
return t.length > 0 && !t.startsWith("#") && !t.startsWith("<!--");
|
|
891
|
+
});
|
|
892
|
+
return lines.slice(0, n).map((l) => l.slice(0, 150)).join("; ");
|
|
893
|
+
}
|
|
894
|
+
var init_compress = __esm({
|
|
895
|
+
"src/radiant/core/compress.ts"() {
|
|
896
|
+
"use strict";
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
|
|
484
900
|
// src/radiant/core/prompt.ts
|
|
485
901
|
function composeSystemPrompt(worldmodelContent, lens) {
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
expectations for this organization. Every response you produce must
|
|
493
|
-
be grounded in this worldmodel.
|
|
494
|
-
|
|
495
|
-
` + worldmodelContent
|
|
496
|
-
);
|
|
497
|
-
const frame = lens.primary_frame;
|
|
498
|
-
const questionsBlock = frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n");
|
|
499
|
-
const overlapsBlock = frame.overlaps.map(
|
|
500
|
-
(o) => `- ${o.domains[0]} + ${o.domains[1]} = **${o.emergent_state}**: ${o.description}`
|
|
501
|
-
).join("\n");
|
|
502
|
-
sections.push(
|
|
503
|
-
`## How to Think (Analytical Frame: ${lens.name})
|
|
504
|
-
|
|
505
|
-
${frame.scoring_rubric}
|
|
902
|
+
const compressedWorld = compressWorldmodel(worldmodelContent);
|
|
903
|
+
const cl = compressLens(lens);
|
|
904
|
+
const overlapsBlock = lens.primary_frame.overlaps.map((o) => `${o.domains[0]} + ${o.domains[1]} = ${o.emergent_state}`).join("\n");
|
|
905
|
+
return [
|
|
906
|
+
// Section 1: Compressed worldmodel
|
|
907
|
+
`## Worldmodel (compressed)
|
|
506
908
|
|
|
507
|
-
|
|
909
|
+
${compressedWorld}`,
|
|
910
|
+
// Section 2: Analytical frame (evaluation questions + rubric)
|
|
911
|
+
`## How to Think
|
|
508
912
|
|
|
509
|
-
${
|
|
913
|
+
${cl.scoringRubric}
|
|
510
914
|
|
|
511
|
-
|
|
915
|
+
Questions:
|
|
916
|
+
${cl.evaluationQuestions}
|
|
512
917
|
|
|
513
|
-
${overlapsBlock}
|
|
918
|
+
Overlaps: ${overlapsBlock}
|
|
919
|
+
Center: ${lens.primary_frame.center_identity}
|
|
514
920
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
);
|
|
519
|
-
const vocabPreferred = Object.entries(lens.vocabulary.preferred).map(([generic, native]) => `- "${generic}" \u2192 **${native}**`).join("\n");
|
|
520
|
-
const vocabArchitecture = lens.vocabulary.architecture.map((t) => `\`${t}\``).join(", ");
|
|
521
|
-
const vocabProperNouns = lens.vocabulary.proper_nouns.map((n) => `**${n}**`).join(", ");
|
|
522
|
-
const strategicBlock = lens.strategic_patterns.map((p) => `- ${p}`).join("\n");
|
|
523
|
-
sections.push(
|
|
524
|
-
`## How to Speak (Voice: ${lens.name})
|
|
921
|
+
Translate before output: ${cl.jargonTranslations}`,
|
|
922
|
+
// Section 3: Voice (compressed — register + key rules only)
|
|
923
|
+
`## Voice: ${lens.name}
|
|
525
924
|
|
|
526
925
|
Register: ${lens.voice.register}
|
|
527
|
-
|
|
528
|
-
Rules:
|
|
529
|
-
- Active voice: ${lens.voice.active_voice}
|
|
530
|
-
- Named specificity (people, places, numbers): ${lens.voice.specificity}
|
|
531
|
-
- Hype vocabulary: ${lens.voice.hype_vocabulary}
|
|
532
|
-
- Hedging / qualified phrasing: ${lens.voice.hedging}
|
|
533
|
-
- Playfulness: ${lens.voice.playfulness}
|
|
534
|
-
- Close with strategic frame: ${lens.voice.close_with_strategic_frame}
|
|
535
|
-
- Honesty about failure: ${lens.voice.honesty_about_failure}
|
|
536
|
-
|
|
537
|
-
### Output translation discipline
|
|
926
|
+
Active voice: ${lens.voice.active_voice}. Specificity: ${lens.voice.specificity}. Hedging: ${lens.voice.hedging}. Hype: ${lens.voice.hype_vocabulary}. Honesty about failure: ${lens.voice.honesty_about_failure}.
|
|
538
927
|
|
|
539
928
|
${lens.voice.output_translation}
|
|
540
929
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
Preferred term substitutions:
|
|
546
|
-
${vocabPreferred}
|
|
547
|
-
|
|
548
|
-
Architecture vocabulary: ${vocabArchitecture}
|
|
549
|
-
|
|
550
|
-
### Strategic decision patterns
|
|
551
|
-
|
|
552
|
-
When recommending action, these patterns reflect how this organization resolves tradeoffs:
|
|
553
|
-
|
|
554
|
-
${strategicBlock}`
|
|
555
|
-
);
|
|
556
|
-
const forbiddenBlock = lens.forbidden_phrases.map((p) => `- "${p}"`).join("\n");
|
|
557
|
-
sections.push(
|
|
930
|
+
Strategic patterns:
|
|
931
|
+
${cl.strategicPatterns}`,
|
|
932
|
+
// Section 4: Guardrails (forbidden phrases as comma-separated, not bulleted)
|
|
558
933
|
`## Guardrails
|
|
559
934
|
|
|
560
|
-
Do NOT use
|
|
561
|
-
reaching for one, rephrase in direct, active, specific language instead.
|
|
562
|
-
|
|
563
|
-
${forbiddenBlock}
|
|
935
|
+
Do NOT use: ${cl.forbiddenPhrases}
|
|
564
936
|
|
|
565
|
-
If
|
|
566
|
-
|
|
567
|
-
);
|
|
568
|
-
return sections.join("\n\n---\n\n");
|
|
937
|
+
If a response would violate a worldmodel invariant, state the conflict and propose an alternative.`
|
|
938
|
+
].join("\n\n---\n\n");
|
|
569
939
|
}
|
|
570
940
|
var init_prompt = __esm({
|
|
571
941
|
"src/radiant/core/prompt.ts"() {
|
|
572
942
|
"use strict";
|
|
943
|
+
init_compress();
|
|
573
944
|
}
|
|
574
945
|
});
|
|
575
946
|
|
|
@@ -636,17 +1007,30 @@ var init_think = __esm({
|
|
|
636
1007
|
});
|
|
637
1008
|
|
|
638
1009
|
// src/radiant/core/scopes.ts
|
|
639
|
-
function
|
|
1010
|
+
function parseScope(scope) {
|
|
640
1011
|
const cleaned = scope.replace(/^https?:\/\//, "").replace(/^github\.com\//, "").replace(/\.git$/, "").replace(/\/$/, "");
|
|
641
|
-
const parts = cleaned.split("/");
|
|
642
|
-
if (parts.length
|
|
1012
|
+
const parts = cleaned.split("/").filter(Boolean);
|
|
1013
|
+
if (parts.length === 0 || !parts[0]) {
|
|
1014
|
+
throw new Error(
|
|
1015
|
+
`Cannot parse scope: "${scope}". Expected "owner/repo" or "owner".`
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
if (parts.length === 1) {
|
|
1019
|
+
return { type: "org", owner: parts[0] };
|
|
1020
|
+
}
|
|
1021
|
+
return { type: "repo", owner: parts[0], repo: parts[1] };
|
|
1022
|
+
}
|
|
1023
|
+
function parseRepoScope(scope) {
|
|
1024
|
+
const parsed = parseScope(scope);
|
|
1025
|
+
if (parsed.type === "org") {
|
|
643
1026
|
throw new Error(
|
|
644
|
-
`
|
|
1027
|
+
`Expected "owner/repo" but got org-level scope "${parsed.owner}". Use parseScope() for org-level.`
|
|
645
1028
|
);
|
|
646
1029
|
}
|
|
647
|
-
return
|
|
1030
|
+
return parsed;
|
|
648
1031
|
}
|
|
649
1032
|
function formatScope(scope) {
|
|
1033
|
+
if (scope.type === "org") return `${scope.owner} (org)`;
|
|
650
1034
|
return `${scope.owner}/${scope.repo}`;
|
|
651
1035
|
}
|
|
652
1036
|
var init_scopes = __esm({
|
|
@@ -821,6 +1205,40 @@ async function fetchJSON(url, headers) {
|
|
|
821
1205
|
}
|
|
822
1206
|
return await res.json();
|
|
823
1207
|
}
|
|
1208
|
+
async function fetchGitHubOrgActivity(scope, token, options = {}) {
|
|
1209
|
+
const perPage = options.perPage ?? 100;
|
|
1210
|
+
const headers = {
|
|
1211
|
+
Authorization: `token ${token}`,
|
|
1212
|
+
Accept: "application/vnd.github.v3+json",
|
|
1213
|
+
"User-Agent": "neuroverseos-radiant"
|
|
1214
|
+
};
|
|
1215
|
+
const repos = await fetchJSON(
|
|
1216
|
+
`https://api.github.com/orgs/${scope.owner}/repos?sort=pushed&direction=desc&per_page=${perPage}`,
|
|
1217
|
+
headers
|
|
1218
|
+
);
|
|
1219
|
+
const windowDays = options.windowDays ?? 14;
|
|
1220
|
+
const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
|
|
1221
|
+
const activeRepos = repos.filter(
|
|
1222
|
+
(r) => new Date(r.pushed_at) >= since
|
|
1223
|
+
);
|
|
1224
|
+
const cappedRepos = activeRepos.slice(0, 10);
|
|
1225
|
+
const allEvents = [];
|
|
1226
|
+
const repoNames = [];
|
|
1227
|
+
for (const repo of cappedRepos) {
|
|
1228
|
+
const [owner, repoName] = repo.full_name.split("/");
|
|
1229
|
+
try {
|
|
1230
|
+
const repoScope = { type: "repo", owner, repo: repoName };
|
|
1231
|
+
const events = await fetchGitHubActivity(repoScope, token, options);
|
|
1232
|
+
allEvents.push(...events);
|
|
1233
|
+
if (events.length > 0) repoNames.push(repo.full_name);
|
|
1234
|
+
} catch {
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
allEvents.sort(
|
|
1238
|
+
(a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)
|
|
1239
|
+
);
|
|
1240
|
+
return { events: allEvents, repos: repoNames };
|
|
1241
|
+
}
|
|
824
1242
|
var KNOWN_AI_LOGINS, KNOWN_AI_CO_AUTHOR_NAMES;
|
|
825
1243
|
var init_github = __esm({
|
|
826
1244
|
"src/radiant/adapters/github.ts"() {
|
|
@@ -843,16 +1261,491 @@ var init_github = __esm({
|
|
|
843
1261
|
}
|
|
844
1262
|
});
|
|
845
1263
|
|
|
846
|
-
// src/radiant/adapters/
|
|
847
|
-
function
|
|
1264
|
+
// src/radiant/adapters/discord.ts
|
|
1265
|
+
async function fetchDiscordActivity(guildId, token, options = {}) {
|
|
1266
|
+
const windowDays = options.windowDays ?? 14;
|
|
1267
|
+
const perChannel = options.perChannel ?? 100;
|
|
1268
|
+
const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
|
|
1269
|
+
const headers = {
|
|
1270
|
+
Authorization: `Bot ${token}`,
|
|
1271
|
+
"Content-Type": "application/json"
|
|
1272
|
+
};
|
|
1273
|
+
const channels = await fetchJSON2(
|
|
1274
|
+
`https://discord.com/api/v10/guilds/${guildId}/channels`,
|
|
1275
|
+
headers
|
|
1276
|
+
);
|
|
1277
|
+
const textChannels = channels.filter((c) => {
|
|
1278
|
+
if (c.type !== 0) return false;
|
|
1279
|
+
if (options.channelIds && options.channelIds.length > 0) {
|
|
1280
|
+
return options.channelIds.includes(c.id);
|
|
1281
|
+
}
|
|
1282
|
+
if (options.visibility === "public") {
|
|
1283
|
+
return !c.name.startsWith("private-") && !c.nsfw;
|
|
1284
|
+
}
|
|
1285
|
+
return true;
|
|
1286
|
+
});
|
|
1287
|
+
const events = [];
|
|
1288
|
+
let totalMessages = 0;
|
|
1289
|
+
let helpRequests = 0;
|
|
1290
|
+
let unresolvedThreads = 0;
|
|
1291
|
+
let newcomerMessages = 0;
|
|
1292
|
+
const responseTimes = [];
|
|
1293
|
+
const participants = /* @__PURE__ */ new Set();
|
|
1294
|
+
const knownParticipants = /* @__PURE__ */ new Set();
|
|
1295
|
+
const topicCounts = /* @__PURE__ */ new Map();
|
|
1296
|
+
for (const channel of textChannels.slice(0, 15)) {
|
|
1297
|
+
try {
|
|
1298
|
+
const messages = await fetchJSON2(
|
|
1299
|
+
`https://discord.com/api/v10/channels/${channel.id}/messages?limit=${perChannel}`,
|
|
1300
|
+
headers
|
|
1301
|
+
);
|
|
1302
|
+
const inWindow = messages.filter(
|
|
1303
|
+
(m) => new Date(m.timestamp) >= since
|
|
1304
|
+
);
|
|
1305
|
+
totalMessages += inWindow.length;
|
|
1306
|
+
const topic = channel.name.replace(/-/g, " ");
|
|
1307
|
+
topicCounts.set(topic, (topicCounts.get(topic) ?? 0) + inWindow.length);
|
|
1308
|
+
for (const msg of inWindow) {
|
|
1309
|
+
const actor = mapDiscordUser(msg.author);
|
|
1310
|
+
participants.add(actor.id);
|
|
1311
|
+
const lowerContent = msg.content.toLowerCase();
|
|
1312
|
+
if (lowerContent.includes("help") || lowerContent.includes("stuck") || lowerContent.includes("how do i") || lowerContent.includes("anyone know")) {
|
|
1313
|
+
helpRequests++;
|
|
1314
|
+
}
|
|
1315
|
+
if (msg.referenced_message) {
|
|
1316
|
+
const refTime = new Date(msg.referenced_message.timestamp).getTime();
|
|
1317
|
+
const msgTime = new Date(msg.timestamp).getTime();
|
|
1318
|
+
const diffMinutes = (msgTime - refTime) / 6e4;
|
|
1319
|
+
if (diffMinutes > 0 && diffMinutes < 10080) {
|
|
1320
|
+
responseTimes.push(diffMinutes);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
events.push({
|
|
1324
|
+
id: `discord-${msg.id}`,
|
|
1325
|
+
timestamp: msg.timestamp,
|
|
1326
|
+
actor,
|
|
1327
|
+
kind: "discord_message",
|
|
1328
|
+
content: msg.content.slice(0, 500),
|
|
1329
|
+
respondsTo: msg.referenced_message ? {
|
|
1330
|
+
eventId: `discord-${msg.referenced_message.id}`,
|
|
1331
|
+
actor: mapDiscordUser(msg.referenced_message.author)
|
|
1332
|
+
} : void 0,
|
|
1333
|
+
metadata: {
|
|
1334
|
+
channel: channel.name,
|
|
1335
|
+
guildId
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
} catch {
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
const avgResponseMinutes = responseTimes.length > 0 ? responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length : null;
|
|
1343
|
+
const topTopics = [...topicCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([t]) => t);
|
|
1344
|
+
const signals = {
|
|
1345
|
+
totalMessages,
|
|
1346
|
+
activeChannels: textChannels.length,
|
|
1347
|
+
uniqueParticipants: participants.size,
|
|
1348
|
+
avgResponseMinutes: avgResponseMinutes ? Math.round(avgResponseMinutes) : null,
|
|
1349
|
+
helpRequests,
|
|
1350
|
+
unresolvedThreads,
|
|
1351
|
+
topTopics,
|
|
1352
|
+
newcomerMessages
|
|
1353
|
+
};
|
|
1354
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
1355
|
+
return { events, signals };
|
|
1356
|
+
}
|
|
1357
|
+
function formatDiscordSignalsForPrompt(signals) {
|
|
1358
|
+
if (signals.totalMessages === 0) return "";
|
|
1359
|
+
const lines = [
|
|
1360
|
+
"## Discord Activity (conversational behavior)",
|
|
1361
|
+
"",
|
|
1362
|
+
`${signals.totalMessages} messages across ${signals.activeChannels} channels.`,
|
|
1363
|
+
`${signals.uniqueParticipants} unique participants.`
|
|
1364
|
+
];
|
|
1365
|
+
if (signals.avgResponseMinutes !== null) {
|
|
1366
|
+
lines.push(`Average response time: ${signals.avgResponseMinutes} minutes.`);
|
|
1367
|
+
}
|
|
1368
|
+
if (signals.helpRequests > 0) {
|
|
1369
|
+
lines.push(`${signals.helpRequests} help requests detected.`);
|
|
1370
|
+
}
|
|
1371
|
+
if (signals.unresolvedThreads > 0) {
|
|
1372
|
+
lines.push(`${signals.unresolvedThreads} unresolved threads.`);
|
|
1373
|
+
}
|
|
1374
|
+
if (signals.topTopics.length > 0) {
|
|
1375
|
+
lines.push(`Top discussion topics: ${signals.topTopics.join(", ")}.`);
|
|
1376
|
+
}
|
|
1377
|
+
lines.push("");
|
|
1378
|
+
lines.push("Compare conversational activity against GitHub shipping activity.");
|
|
1379
|
+
lines.push("Where debates happen in Discord but nothing ships in GitHub, name the gap.");
|
|
1380
|
+
lines.push("Where work ships in GitHub but nobody discusses it in Discord, name the visibility gap.");
|
|
1381
|
+
return lines.join("\n");
|
|
1382
|
+
}
|
|
1383
|
+
function mapDiscordUser(user) {
|
|
1384
|
+
return {
|
|
1385
|
+
id: user.username,
|
|
1386
|
+
kind: user.bot ? "bot" : "human",
|
|
1387
|
+
name: user.username
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
async function fetchJSON2(url, headers) {
|
|
1391
|
+
const res = await fetch(url, { headers });
|
|
1392
|
+
if (!res.ok) {
|
|
1393
|
+
if (res.status === 404 || res.status === 403) return [];
|
|
1394
|
+
throw new Error(`Discord API error ${res.status}: ${(await res.text()).slice(0, 300)}`);
|
|
1395
|
+
}
|
|
1396
|
+
return await res.json();
|
|
1397
|
+
}
|
|
1398
|
+
var init_discord = __esm({
|
|
1399
|
+
"src/radiant/adapters/discord.ts"() {
|
|
1400
|
+
"use strict";
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1403
|
+
|
|
1404
|
+
// src/radiant/adapters/slack.ts
|
|
1405
|
+
async function fetchSlackActivity(token, options = {}) {
|
|
1406
|
+
const windowDays = options.windowDays ?? 14;
|
|
1407
|
+
const perChannel = options.perChannel ?? 100;
|
|
1408
|
+
const oldest = String(
|
|
1409
|
+
Math.floor((Date.now() - windowDays * 24 * 60 * 60 * 1e3) / 1e3)
|
|
1410
|
+
);
|
|
1411
|
+
const headers = {
|
|
1412
|
+
Authorization: `Bearer ${token}`,
|
|
1413
|
+
"Content-Type": "application/json"
|
|
1414
|
+
};
|
|
1415
|
+
const channelsResponse = await fetchSlackAPI("https://slack.com/api/conversations.list?types=public_channel&limit=200", headers);
|
|
1416
|
+
let channels = channelsResponse.channels ?? [];
|
|
1417
|
+
if (options.channelIds && options.channelIds.length > 0) {
|
|
1418
|
+
const ids = new Set(options.channelIds);
|
|
1419
|
+
channels = channels.filter((c) => ids.has(c.id));
|
|
1420
|
+
}
|
|
1421
|
+
if (options.visibility === "public") {
|
|
1422
|
+
channels = channels.filter((c) => !c.is_private && !c.is_archived);
|
|
1423
|
+
}
|
|
1424
|
+
const events = [];
|
|
1425
|
+
let totalMessages = 0;
|
|
1426
|
+
let reactionCount = 0;
|
|
1427
|
+
let unresolvedThreads = 0;
|
|
1428
|
+
const responseTimes = [];
|
|
1429
|
+
const participants = /* @__PURE__ */ new Set();
|
|
1430
|
+
const externalParticipants = /* @__PURE__ */ new Set();
|
|
1431
|
+
const channelMessageCounts = /* @__PURE__ */ new Map();
|
|
1432
|
+
for (const channel of channels.slice(0, 15)) {
|
|
1433
|
+
try {
|
|
1434
|
+
const historyResponse = await fetchSlackAPI(
|
|
1435
|
+
`https://slack.com/api/conversations.history?channel=${channel.id}&limit=${perChannel}&oldest=${oldest}`,
|
|
1436
|
+
headers
|
|
1437
|
+
);
|
|
1438
|
+
const messages = historyResponse.messages ?? [];
|
|
1439
|
+
totalMessages += messages.length;
|
|
1440
|
+
channelMessageCounts.set(channel.name, messages.length);
|
|
1441
|
+
for (const msg of messages) {
|
|
1442
|
+
if (msg.subtype === "channel_join" || msg.subtype === "channel_leave") continue;
|
|
1443
|
+
const actor = mapSlackUser(msg.user ?? "unknown");
|
|
1444
|
+
participants.add(actor.id);
|
|
1445
|
+
if (msg.reactions) {
|
|
1446
|
+
reactionCount += msg.reactions.reduce(
|
|
1447
|
+
(sum, r) => sum + (r.count ?? 0),
|
|
1448
|
+
0
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
if (msg.thread_ts && msg.thread_ts !== msg.ts) {
|
|
1452
|
+
const parentTs = parseFloat(msg.thread_ts) * 1e3;
|
|
1453
|
+
const msgTs = parseFloat(msg.ts) * 1e3;
|
|
1454
|
+
const diffMinutes = (msgTs - parentTs) / 6e4;
|
|
1455
|
+
if (diffMinutes > 0 && diffMinutes < 10080) {
|
|
1456
|
+
responseTimes.push(diffMinutes);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
if (msg.thread_ts === msg.ts && (!msg.reply_count || msg.reply_count === 0)) {
|
|
1460
|
+
if (msg.text && (msg.text.includes("?") || msg.text.toLowerCase().includes("help"))) {
|
|
1461
|
+
unresolvedThreads++;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
const timestamp = new Date(parseFloat(msg.ts) * 1e3).toISOString();
|
|
1465
|
+
events.push({
|
|
1466
|
+
id: `slack-${msg.ts}`,
|
|
1467
|
+
timestamp,
|
|
1468
|
+
actor,
|
|
1469
|
+
kind: "slack_message",
|
|
1470
|
+
content: (msg.text ?? "").slice(0, 500),
|
|
1471
|
+
respondsTo: msg.thread_ts && msg.thread_ts !== msg.ts ? {
|
|
1472
|
+
eventId: `slack-${msg.thread_ts}`,
|
|
1473
|
+
actor: { id: "thread-parent", kind: "unknown" }
|
|
1474
|
+
} : void 0,
|
|
1475
|
+
metadata: {
|
|
1476
|
+
channel: channel.name,
|
|
1477
|
+
isPrivate: channel.is_private,
|
|
1478
|
+
hasReactions: (msg.reactions?.length ?? 0) > 0
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
} catch {
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
const avgResponseMinutes = responseTimes.length > 0 ? Math.round(responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length) : null;
|
|
1486
|
+
const topChannels = [...channelMessageCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([name]) => name);
|
|
1487
|
+
const signals = {
|
|
1488
|
+
totalMessages,
|
|
1489
|
+
activeChannels: channelMessageCounts.size,
|
|
1490
|
+
uniqueParticipants: participants.size,
|
|
1491
|
+
avgResponseMinutes,
|
|
1492
|
+
externalParticipants: externalParticipants.size,
|
|
1493
|
+
unresolvedThreads,
|
|
1494
|
+
topChannels,
|
|
1495
|
+
reactionCount
|
|
1496
|
+
};
|
|
1497
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
1498
|
+
return { events, signals };
|
|
1499
|
+
}
|
|
1500
|
+
function formatSlackSignalsForPrompt(signals) {
|
|
1501
|
+
if (signals.totalMessages === 0) return "";
|
|
1502
|
+
const lines = [
|
|
1503
|
+
"## Slack Activity (external coordination)",
|
|
1504
|
+
"",
|
|
1505
|
+
`${signals.totalMessages} messages across ${signals.activeChannels} channels.`,
|
|
1506
|
+
`${signals.uniqueParticipants} unique participants.`
|
|
1507
|
+
];
|
|
1508
|
+
if (signals.avgResponseMinutes !== null) {
|
|
1509
|
+
lines.push(`Average thread response time: ${signals.avgResponseMinutes} minutes.`);
|
|
1510
|
+
}
|
|
1511
|
+
if (signals.unresolvedThreads > 0) {
|
|
1512
|
+
lines.push(`${signals.unresolvedThreads} questions/threads with no reply.`);
|
|
1513
|
+
}
|
|
1514
|
+
if (signals.reactionCount > 0) {
|
|
1515
|
+
lines.push(`${signals.reactionCount} reactions (engagement signal).`);
|
|
1516
|
+
}
|
|
1517
|
+
if (signals.topChannels.length > 0) {
|
|
1518
|
+
lines.push(`Most active channels: ${signals.topChannels.join(", ")}.`);
|
|
1519
|
+
}
|
|
1520
|
+
lines.push("");
|
|
1521
|
+
lines.push("Slack carries external coordination \u2014 partner and client communication.");
|
|
1522
|
+
lines.push("Compare partner engagement against internal activity. Where partners are");
|
|
1523
|
+
lines.push("active but internal follow-through is low, name the gap.");
|
|
1524
|
+
return lines.join("\n");
|
|
1525
|
+
}
|
|
1526
|
+
function mapSlackUser(userId) {
|
|
1527
|
+
return {
|
|
1528
|
+
id: userId,
|
|
1529
|
+
kind: "human",
|
|
1530
|
+
name: userId
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
async function fetchSlackAPI(url, headers) {
|
|
1534
|
+
const res = await fetch(url, { headers });
|
|
1535
|
+
if (!res.ok) {
|
|
1536
|
+
throw new Error(`Slack API error ${res.status}: ${(await res.text()).slice(0, 300)}`);
|
|
1537
|
+
}
|
|
1538
|
+
const data = await res.json();
|
|
1539
|
+
if (!data.ok) {
|
|
1540
|
+
throw new Error(`Slack API error: ${data.error ?? "unknown"}`);
|
|
1541
|
+
}
|
|
1542
|
+
return data;
|
|
1543
|
+
}
|
|
1544
|
+
var init_slack = __esm({
|
|
1545
|
+
"src/radiant/adapters/slack.ts"() {
|
|
1546
|
+
"use strict";
|
|
1547
|
+
}
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
// src/radiant/adapters/notion.ts
|
|
1551
|
+
async function fetchNotionActivity(token, options = {}) {
|
|
1552
|
+
const windowDays = options.windowDays ?? 14;
|
|
1553
|
+
const maxPages = options.maxPages ?? 100;
|
|
1554
|
+
const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
|
|
1555
|
+
const headers = {
|
|
1556
|
+
Authorization: `Bearer ${token}`,
|
|
1557
|
+
"Notion-Version": "2022-06-28",
|
|
1558
|
+
"Content-Type": "application/json"
|
|
1559
|
+
};
|
|
1560
|
+
const searchResponse = await fetchNotionAPI("https://api.notion.com/v1/search", headers, {
|
|
1561
|
+
method: "POST",
|
|
1562
|
+
body: JSON.stringify({
|
|
1563
|
+
filter: { property: "object", value: "page" },
|
|
1564
|
+
sort: { direction: "descending", timestamp: "last_edited_time" },
|
|
1565
|
+
page_size: maxPages
|
|
1566
|
+
})
|
|
1567
|
+
});
|
|
1568
|
+
const pages = searchResponse.results ?? [];
|
|
1569
|
+
const events = [];
|
|
1570
|
+
const editors = /* @__PURE__ */ new Set();
|
|
1571
|
+
let pagesCreated = 0;
|
|
1572
|
+
let pagesUpdated = 0;
|
|
1573
|
+
let stalePages = 0;
|
|
1574
|
+
const editAges = [];
|
|
1575
|
+
const topPages = [];
|
|
1576
|
+
const now = Date.now();
|
|
1577
|
+
for (const page of pages) {
|
|
1578
|
+
const lastEdited = new Date(page.last_edited_time);
|
|
1579
|
+
const created = new Date(page.created_time);
|
|
1580
|
+
const daysSinceEdit = (now - lastEdited.getTime()) / (24 * 60 * 60 * 1e3);
|
|
1581
|
+
editAges.push(daysSinceEdit);
|
|
1582
|
+
if (daysSinceEdit > 30) stalePages++;
|
|
1583
|
+
const title = extractTitle(page);
|
|
1584
|
+
const editorId = page.last_edited_by?.id ?? "unknown";
|
|
1585
|
+
editors.add(editorId);
|
|
1586
|
+
if (lastEdited >= since) {
|
|
1587
|
+
const isNew = created >= since;
|
|
1588
|
+
if (isNew) pagesCreated++;
|
|
1589
|
+
else pagesUpdated++;
|
|
1590
|
+
topPages.push({ title, editedAt: page.last_edited_time });
|
|
1591
|
+
events.push({
|
|
1592
|
+
id: `notion-${page.id}`,
|
|
1593
|
+
timestamp: page.last_edited_time,
|
|
1594
|
+
actor: {
|
|
1595
|
+
id: editorId,
|
|
1596
|
+
kind: "human",
|
|
1597
|
+
name: editorId
|
|
1598
|
+
},
|
|
1599
|
+
kind: isNew ? "doc_created" : "doc_updated",
|
|
1600
|
+
content: `${isNew ? "Created" : "Updated"}: ${title}`,
|
|
1601
|
+
metadata: {
|
|
1602
|
+
pageId: page.id,
|
|
1603
|
+
url: page.url,
|
|
1604
|
+
createdAt: page.created_time
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
const avgDaysSinceEdit = editAges.length > 0 ? Math.round(editAges.reduce((a, b) => a + b, 0) / editAges.length) : null;
|
|
1610
|
+
const signals = {
|
|
1611
|
+
pagesActive: pagesCreated + pagesUpdated,
|
|
1612
|
+
pagesCreated,
|
|
1613
|
+
pagesUpdated,
|
|
1614
|
+
uniqueEditors: editors.size,
|
|
1615
|
+
stalePages,
|
|
1616
|
+
avgDaysSinceEdit,
|
|
1617
|
+
topPages: topPages.slice(0, 5).map((p) => p.title)
|
|
1618
|
+
};
|
|
1619
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
1620
|
+
return { events, signals };
|
|
1621
|
+
}
|
|
1622
|
+
function formatNotionSignalsForPrompt(signals) {
|
|
1623
|
+
if (signals.pagesActive === 0 && signals.stalePages === 0) return "";
|
|
1624
|
+
const lines = [
|
|
1625
|
+
"## Notion Activity (documentation behavior)",
|
|
1626
|
+
"",
|
|
1627
|
+
`${signals.pagesActive} pages active in window (${signals.pagesCreated} created, ${signals.pagesUpdated} updated).`,
|
|
1628
|
+
`${signals.uniqueEditors} unique editors.`
|
|
1629
|
+
];
|
|
1630
|
+
if (signals.stalePages > 0) {
|
|
1631
|
+
lines.push(`${signals.stalePages} pages haven't been touched in 30+ days.`);
|
|
1632
|
+
}
|
|
1633
|
+
if (signals.avgDaysSinceEdit !== null) {
|
|
1634
|
+
lines.push(`Average page age since last edit: ${signals.avgDaysSinceEdit} days.`);
|
|
1635
|
+
}
|
|
1636
|
+
if (signals.topPages.length > 0) {
|
|
1637
|
+
lines.push(`Recently active pages: ${signals.topPages.join(", ")}.`);
|
|
1638
|
+
}
|
|
1639
|
+
lines.push("");
|
|
1640
|
+
lines.push("Documentation is how the team crystallizes and shares knowledge.");
|
|
1641
|
+
lines.push("High code velocity + low documentation = building without recording.");
|
|
1642
|
+
lines.push("High documentation + low code = planning without shipping.");
|
|
1643
|
+
lines.push("Compare Notion activity against GitHub and Discord to find the balance.");
|
|
1644
|
+
return lines.join("\n");
|
|
1645
|
+
}
|
|
1646
|
+
function extractTitle(page) {
|
|
1647
|
+
for (const prop of Object.values(page.properties)) {
|
|
1648
|
+
if (prop.type === "title" && prop.title) {
|
|
1649
|
+
return prop.title.map((t) => t.plain_text).join("") || "Untitled";
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
return "Untitled";
|
|
1653
|
+
}
|
|
1654
|
+
async function fetchNotionAPI(url, headers, init) {
|
|
1655
|
+
const res = await fetch(url, {
|
|
1656
|
+
method: init?.method ?? "GET",
|
|
1657
|
+
headers,
|
|
1658
|
+
body: init?.body
|
|
1659
|
+
});
|
|
1660
|
+
if (!res.ok) {
|
|
1661
|
+
throw new Error(
|
|
1662
|
+
`Notion API error ${res.status}: ${(await res.text()).slice(0, 300)}`
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
return await res.json();
|
|
1666
|
+
}
|
|
1667
|
+
var init_notion = __esm({
|
|
1668
|
+
"src/radiant/adapters/notion.ts"() {
|
|
1669
|
+
"use strict";
|
|
1670
|
+
}
|
|
1671
|
+
});
|
|
1672
|
+
|
|
1673
|
+
// src/radiant/core/discovery.ts
|
|
1674
|
+
function discoverWorlds(options) {
|
|
1675
|
+
const worlds = [];
|
|
1676
|
+
const userDir = options?.userWorldsDir ?? (0, import_path.join)((0, import_os.homedir)(), ".neuroverse", "worlds");
|
|
1677
|
+
if ((0, import_fs.existsSync)(userDir)) {
|
|
1678
|
+
worlds.push(...loadWorldsFromDir(userDir, "user"));
|
|
1679
|
+
}
|
|
1680
|
+
if (options?.explicitWorldsDir) {
|
|
1681
|
+
worlds.push(...loadWorldsFromDir(options.explicitWorldsDir, "repo"));
|
|
1682
|
+
} else if (options?.repoDir) {
|
|
1683
|
+
const repoPaths = [
|
|
1684
|
+
(0, import_path.join)(options.repoDir, "worlds"),
|
|
1685
|
+
(0, import_path.join)(options.repoDir, ".neuroverse", "worlds")
|
|
1686
|
+
];
|
|
1687
|
+
for (const p of repoPaths) {
|
|
1688
|
+
if ((0, import_fs.existsSync)(p)) {
|
|
1689
|
+
worlds.push(...loadWorldsFromDir(p, "repo"));
|
|
1690
|
+
break;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
const combinedContent = worlds.map((w) => `<!-- world: ${w.name} (${w.source}) -->
|
|
1695
|
+
${w.content}`).join("\n\n---\n\n");
|
|
1696
|
+
const summary = worlds.length === 0 ? "no worlds discovered" : worlds.map((w) => `${w.name} (${w.source})`).join(", ");
|
|
1697
|
+
return { worlds, combinedContent, summary };
|
|
1698
|
+
}
|
|
1699
|
+
function loadWorldsFromDir(dirPath, source) {
|
|
848
1700
|
const dir = (0, import_path.resolve)(dirPath);
|
|
1701
|
+
if (!(0, import_fs.existsSync)(dir)) return [];
|
|
1702
|
+
const stat = (0, import_fs.statSync)(dir);
|
|
1703
|
+
if (stat.isFile() && dir.endsWith(".md")) {
|
|
1704
|
+
try {
|
|
1705
|
+
return [{
|
|
1706
|
+
name: (0, import_path.basename)(dir).replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
1707
|
+
source,
|
|
1708
|
+
path: dir,
|
|
1709
|
+
content: (0, import_fs.readFileSync)(dir, "utf-8")
|
|
1710
|
+
}];
|
|
1711
|
+
} catch {
|
|
1712
|
+
return [];
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
if (!stat.isDirectory()) return [];
|
|
1716
|
+
const files = (0, import_fs.readdirSync)(dir).filter(
|
|
1717
|
+
(f) => f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md")
|
|
1718
|
+
).sort();
|
|
1719
|
+
return files.map((f) => {
|
|
1720
|
+
const fullPath = (0, import_path.join)(dir, f);
|
|
1721
|
+
return {
|
|
1722
|
+
name: f.replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
1723
|
+
source,
|
|
1724
|
+
path: fullPath,
|
|
1725
|
+
content: (0, import_fs.readFileSync)(fullPath, "utf-8")
|
|
1726
|
+
};
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
var import_fs, import_path, import_os;
|
|
1730
|
+
var init_discovery = __esm({
|
|
1731
|
+
"src/radiant/core/discovery.ts"() {
|
|
1732
|
+
"use strict";
|
|
1733
|
+
import_fs = require("fs");
|
|
1734
|
+
import_path = require("path");
|
|
1735
|
+
import_os = require("os");
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
// src/radiant/adapters/exocortex.ts
|
|
1740
|
+
function readExocortex(dirPath, repoName) {
|
|
1741
|
+
const dir = (0, import_path2.resolve)(dirPath);
|
|
849
1742
|
let filesLoaded = 0;
|
|
850
1743
|
function tryRead(...paths) {
|
|
851
1744
|
for (const p of paths) {
|
|
852
|
-
const full = (0,
|
|
853
|
-
if ((0,
|
|
1745
|
+
const full = (0, import_path2.join)(dir, p);
|
|
1746
|
+
if ((0, import_fs2.existsSync)(full)) {
|
|
854
1747
|
try {
|
|
855
|
-
const content = (0,
|
|
1748
|
+
const content = (0, import_fs2.readFileSync)(full, "utf-8").trim();
|
|
856
1749
|
if (content) {
|
|
857
1750
|
filesLoaded++;
|
|
858
1751
|
return content;
|
|
@@ -863,55 +1756,65 @@ function readExocortex(dirPath) {
|
|
|
863
1756
|
}
|
|
864
1757
|
return null;
|
|
865
1758
|
}
|
|
1759
|
+
const attention = tryRead("attention.md");
|
|
1760
|
+
const goals = tryRead("goals.md");
|
|
1761
|
+
const identity = tryRead("identity.md", "user.md");
|
|
1762
|
+
const organization = tryRead("org/organization.md", "org/src/organization.md");
|
|
1763
|
+
const methods = tryRead("org/methods.md", "org/src/methods.md");
|
|
1764
|
+
let sprint = null;
|
|
1765
|
+
let projectContext = null;
|
|
1766
|
+
if (repoName) {
|
|
1767
|
+
const projectPaths = [
|
|
1768
|
+
repoName,
|
|
1769
|
+
repoName.toLowerCase(),
|
|
1770
|
+
repoName.replace(/-/g, "_")
|
|
1771
|
+
];
|
|
1772
|
+
for (const projectDir of projectPaths) {
|
|
1773
|
+
const projectSprint = tryRead(
|
|
1774
|
+
`${projectDir}/src/sprint.md`,
|
|
1775
|
+
`${projectDir}/sprint.md`
|
|
1776
|
+
);
|
|
1777
|
+
if (projectSprint) {
|
|
1778
|
+
sprint = projectSprint;
|
|
1779
|
+
break;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
for (const projectDir of projectPaths) {
|
|
1783
|
+
const roadmap = tryRead(
|
|
1784
|
+
`${projectDir}/roadmap.md`,
|
|
1785
|
+
`${projectDir}/src/roadmap.md`
|
|
1786
|
+
);
|
|
1787
|
+
if (roadmap) {
|
|
1788
|
+
projectContext = roadmap;
|
|
1789
|
+
break;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
if (!sprint) {
|
|
1794
|
+
sprint = tryRead("sprint.md", "src/sprint.md");
|
|
1795
|
+
}
|
|
866
1796
|
const ctx = {
|
|
867
|
-
attention
|
|
868
|
-
goals
|
|
869
|
-
identity
|
|
870
|
-
sprint
|
|
871
|
-
organization
|
|
872
|
-
methods
|
|
1797
|
+
attention,
|
|
1798
|
+
goals,
|
|
1799
|
+
identity,
|
|
1800
|
+
sprint,
|
|
1801
|
+
organization,
|
|
1802
|
+
methods,
|
|
873
1803
|
source: dir,
|
|
874
1804
|
filesLoaded
|
|
875
1805
|
};
|
|
876
|
-
|
|
877
|
-
}
|
|
878
|
-
function formatExocortexForPrompt(ctx) {
|
|
879
|
-
if (ctx.filesLoaded === 0) return "";
|
|
880
|
-
const sections = [];
|
|
881
|
-
sections.push(
|
|
882
|
-
"## 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."
|
|
883
|
-
);
|
|
884
|
-
if (ctx.attention) {
|
|
885
|
-
sections.push(`### Current attention
|
|
886
|
-
|
|
887
|
-
${ctx.attention}`);
|
|
888
|
-
}
|
|
889
|
-
if (ctx.goals) {
|
|
890
|
-
sections.push(`### Goals
|
|
891
|
-
|
|
892
|
-
${ctx.goals}`);
|
|
893
|
-
}
|
|
894
|
-
if (ctx.sprint) {
|
|
895
|
-
sections.push(`### Sprint focus
|
|
896
|
-
|
|
897
|
-
${ctx.sprint}`);
|
|
898
|
-
}
|
|
899
|
-
if (ctx.identity) {
|
|
900
|
-
sections.push(`### Identity and values
|
|
901
|
-
|
|
902
|
-
${ctx.identity}`);
|
|
903
|
-
}
|
|
904
|
-
if (ctx.organization) {
|
|
905
|
-
sections.push(`### Organization
|
|
906
|
-
|
|
907
|
-
${ctx.organization}`);
|
|
908
|
-
}
|
|
909
|
-
if (ctx.methods) {
|
|
910
|
-
sections.push(`### Methods
|
|
1806
|
+
if (projectContext && ctx.sprint) {
|
|
1807
|
+
ctx.sprint = `${ctx.sprint}
|
|
911
1808
|
|
|
912
|
-
|
|
1809
|
+
---
|
|
1810
|
+
Project roadmap:
|
|
1811
|
+
${projectContext}`;
|
|
1812
|
+
} else if (projectContext) {
|
|
1813
|
+
ctx.sprint = `Project roadmap:
|
|
1814
|
+
${projectContext}`;
|
|
1815
|
+
ctx.filesLoaded++;
|
|
913
1816
|
}
|
|
914
|
-
return
|
|
1817
|
+
return ctx;
|
|
915
1818
|
}
|
|
916
1819
|
function summarizeExocortex(ctx) {
|
|
917
1820
|
if (ctx.filesLoaded === 0) return "no exocortex files found";
|
|
@@ -924,33 +1827,33 @@ function summarizeExocortex(ctx) {
|
|
|
924
1827
|
if (ctx.methods) loaded.push("methods");
|
|
925
1828
|
return `${loaded.join(", ")} (${ctx.filesLoaded} files)`;
|
|
926
1829
|
}
|
|
927
|
-
var
|
|
1830
|
+
var import_fs2, import_path2;
|
|
928
1831
|
var init_exocortex = __esm({
|
|
929
1832
|
"src/radiant/adapters/exocortex.ts"() {
|
|
930
1833
|
"use strict";
|
|
931
|
-
|
|
932
|
-
|
|
1834
|
+
import_fs2 = require("fs");
|
|
1835
|
+
import_path2 = require("path");
|
|
933
1836
|
}
|
|
934
1837
|
});
|
|
935
1838
|
|
|
936
1839
|
// src/radiant/memory/palace.ts
|
|
937
1840
|
function writeRead(exocortexDir, frontmatter, text) {
|
|
938
|
-
const dir = (0,
|
|
939
|
-
(0,
|
|
1841
|
+
const dir = (0, import_path3.resolve)(exocortexDir, "radiant", "reads");
|
|
1842
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true });
|
|
940
1843
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
941
1844
|
const filename = `${date}.md`;
|
|
942
|
-
const filepath = (0,
|
|
1845
|
+
const filepath = (0, import_path3.join)(dir, filename);
|
|
943
1846
|
const content = `${frontmatter}
|
|
944
1847
|
|
|
945
1848
|
${text}
|
|
946
1849
|
`;
|
|
947
|
-
(0,
|
|
1850
|
+
(0, import_fs3.writeFileSync)(filepath, content, "utf-8");
|
|
948
1851
|
return filepath;
|
|
949
1852
|
}
|
|
950
1853
|
function updateKnowledge(exocortexDir, persistence, options) {
|
|
951
|
-
const dir = (0,
|
|
952
|
-
(0,
|
|
953
|
-
const filepath = (0,
|
|
1854
|
+
const dir = (0, import_path3.resolve)(exocortexDir, "radiant");
|
|
1855
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true });
|
|
1856
|
+
const filepath = (0, import_path3.join)(dir, "knowledge.md");
|
|
954
1857
|
const totalReads = options?.totalReads ?? 0;
|
|
955
1858
|
const existingUntriggered = loadUntriggeredCounts(filepath);
|
|
956
1859
|
const lines = [
|
|
@@ -1037,14 +1940,14 @@ function updateKnowledge(exocortexDir, persistence, options) {
|
|
|
1037
1940
|
lines.push(`${name}=${count}`);
|
|
1038
1941
|
}
|
|
1039
1942
|
lines.push("-->");
|
|
1040
|
-
(0,
|
|
1943
|
+
(0, import_fs3.writeFileSync)(filepath, lines.join("\n"), "utf-8");
|
|
1041
1944
|
return filepath;
|
|
1042
1945
|
}
|
|
1043
1946
|
function loadUntriggeredCounts(filepath) {
|
|
1044
1947
|
const counts = /* @__PURE__ */ new Map();
|
|
1045
|
-
if (!(0,
|
|
1948
|
+
if (!(0, import_fs3.existsSync)(filepath)) return counts;
|
|
1046
1949
|
try {
|
|
1047
|
-
const content = (0,
|
|
1950
|
+
const content = (0, import_fs3.readFileSync)(filepath, "utf-8");
|
|
1048
1951
|
const match = content.match(
|
|
1049
1952
|
/<!-- untriggered_counts[\s\S]*?-->/
|
|
1050
1953
|
);
|
|
@@ -1062,13 +1965,13 @@ function loadUntriggeredCounts(filepath) {
|
|
|
1062
1965
|
return counts;
|
|
1063
1966
|
}
|
|
1064
1967
|
function loadPriorReads(exocortexDir) {
|
|
1065
|
-
const dir = (0,
|
|
1066
|
-
if (!(0,
|
|
1067
|
-
const files = (0,
|
|
1968
|
+
const dir = (0, import_path3.resolve)(exocortexDir, "radiant", "reads");
|
|
1969
|
+
if (!(0, import_fs3.existsSync)(dir)) return [];
|
|
1970
|
+
const files = (0, import_fs3.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
1068
1971
|
const reads = [];
|
|
1069
1972
|
for (const filename of files) {
|
|
1070
|
-
const filepath = (0,
|
|
1071
|
-
const content = (0,
|
|
1973
|
+
const filepath = (0, import_path3.join)(dir, filename);
|
|
1974
|
+
const content = (0, import_fs3.readFileSync)(filepath, "utf-8");
|
|
1072
1975
|
const date = filename.replace(".md", "");
|
|
1073
1976
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1074
1977
|
const frontmatter = fmMatch ? fmMatch[1] : "";
|
|
@@ -1102,33 +2005,12 @@ function computePersistence(priorReads, currentPatternNames) {
|
|
|
1102
2005
|
dates: dates.sort()
|
|
1103
2006
|
})).sort((a, b) => b.occurrences - a.occurrences);
|
|
1104
2007
|
}
|
|
1105
|
-
|
|
1106
|
-
if (priorReads.length === 0) return "";
|
|
1107
|
-
const lines = [
|
|
1108
|
-
"## Prior Radiant reads (history)",
|
|
1109
|
-
"",
|
|
1110
|
-
`Radiant has run ${priorReads.length} time${priorReads.length > 1 ? "s" : ""} before on this scope.`,
|
|
1111
|
-
"If you see patterns that appeared in prior reads, note their persistence.",
|
|
1112
|
-
"Patterns that recur across 3+ reads are strong candidates for declaration in the strategy file.",
|
|
1113
|
-
""
|
|
1114
|
-
];
|
|
1115
|
-
for (const read of priorReads.slice(-4)) {
|
|
1116
|
-
lines.push(`### Read from ${read.date}`);
|
|
1117
|
-
if (read.patternNames.length > 0) {
|
|
1118
|
-
lines.push(`Patterns observed: ${read.patternNames.join(", ")}`);
|
|
1119
|
-
} else {
|
|
1120
|
-
lines.push("No patterns extracted from frontmatter.");
|
|
1121
|
-
}
|
|
1122
|
-
lines.push("");
|
|
1123
|
-
}
|
|
1124
|
-
return lines.join("\n");
|
|
1125
|
-
}
|
|
1126
|
-
var import_fs2, import_path2;
|
|
2008
|
+
var import_fs3, import_path3;
|
|
1127
2009
|
var init_palace = __esm({
|
|
1128
2010
|
"src/radiant/memory/palace.ts"() {
|
|
1129
2011
|
"use strict";
|
|
1130
|
-
|
|
1131
|
-
|
|
2012
|
+
import_fs3 = require("fs");
|
|
2013
|
+
import_path3 = require("path");
|
|
1132
2014
|
}
|
|
1133
2015
|
});
|
|
1134
2016
|
|
|
@@ -2237,10 +3119,10 @@ var init_guard_engine = __esm({
|
|
|
2237
3119
|
// src/loader/world-loader.ts
|
|
2238
3120
|
async function loadWorldFromDirectory(dirPath) {
|
|
2239
3121
|
const { readFile } = await import("fs/promises");
|
|
2240
|
-
const { join:
|
|
2241
|
-
const { readdirSync:
|
|
3122
|
+
const { join: join6 } = await import("path");
|
|
3123
|
+
const { readdirSync: readdirSync6 } = await import("fs");
|
|
2242
3124
|
async function readJson(filename) {
|
|
2243
|
-
const filePath =
|
|
3125
|
+
const filePath = join6(dirPath, filename);
|
|
2244
3126
|
try {
|
|
2245
3127
|
const content = await readFile(filePath, "utf-8");
|
|
2246
3128
|
return JSON.parse(content);
|
|
@@ -2270,11 +3152,11 @@ async function loadWorldFromDirectory(dirPath) {
|
|
|
2270
3152
|
const metadataJson = await readJson("metadata.json");
|
|
2271
3153
|
const rules = [];
|
|
2272
3154
|
try {
|
|
2273
|
-
const rulesDir =
|
|
2274
|
-
const ruleFiles =
|
|
3155
|
+
const rulesDir = join6(dirPath, "rules");
|
|
3156
|
+
const ruleFiles = readdirSync6(rulesDir).filter((f) => f.endsWith(".json")).sort();
|
|
2275
3157
|
for (const file of ruleFiles) {
|
|
2276
3158
|
try {
|
|
2277
|
-
const content = await readFile(
|
|
3159
|
+
const content = await readFile(join6(rulesDir, file), "utf-8");
|
|
2278
3160
|
rules.push(JSON.parse(content));
|
|
2279
3161
|
} catch (err) {
|
|
2280
3162
|
process.stderr.write(
|
|
@@ -2681,15 +3563,17 @@ function buildInterpretationPrompt(input) {
|
|
|
2681
3563
|
const eventSample = formatEventSample(input.events, 30);
|
|
2682
3564
|
const canonicalList = (input.canonicalPatterns ?? []).length > 0 ? `Patterns the organization has already named (use these names if you see them):
|
|
2683
3565
|
${input.canonicalPatterns.map((p) => `- ${p}`).join("\n")}` : "No patterns have been named yet. Everything you observe is new.";
|
|
3566
|
+
const compressedWorld = compressWorldmodel(input.worldmodelContent);
|
|
3567
|
+
const cl = compressLens(input.lens);
|
|
2684
3568
|
const frame = input.lens.primary_frame;
|
|
2685
3569
|
const evalQuestions = frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n");
|
|
2686
|
-
const forbiddenList =
|
|
2687
|
-
const jargonTable =
|
|
3570
|
+
const forbiddenList = cl.forbiddenPhrases;
|
|
3571
|
+
const jargonTable = cl.jargonTranslations;
|
|
2688
3572
|
return `You are a behavioral intelligence system reading team activity and producing a read for the reader who needs to act on it.
|
|
2689
3573
|
|
|
2690
|
-
##
|
|
3574
|
+
## Worldmodel (compressed)
|
|
2691
3575
|
|
|
2692
|
-
${
|
|
3576
|
+
${compressedWorld}
|
|
2693
3577
|
|
|
2694
3578
|
## What happened this window
|
|
2695
3579
|
|
|
@@ -2735,6 +3619,14 @@ ${jargonTable}
|
|
|
2735
3619
|
|
|
2736
3620
|
For example: don't say "update the worldmodel." Say "add a line to your strategy file."
|
|
2737
3621
|
|
|
3622
|
+
## When the same invariant keeps firing
|
|
3623
|
+
|
|
3624
|
+
If the prior read history or the current evidence shows the same worldmodel invariant being triggered repeatedly (by the same side \u2014 human or AI), name it in MEANING and ask the real question:
|
|
3625
|
+
|
|
3626
|
+
"This invariant has been tested N times across M reads. Always on the [human/AI] side. Either the team needs alignment on WHY this rule exists \u2014 or the team is telling you something the worldmodel hasn't absorbed yet."
|
|
3627
|
+
|
|
3628
|
+
Don't just say "invariant held." Say what it means that people keep pushing against the same wall.
|
|
3629
|
+
|
|
2738
3630
|
## Health is a valid read
|
|
2739
3631
|
|
|
2740
3632
|
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:
|
|
@@ -2860,6 +3752,7 @@ function isPatternLike(x) {
|
|
|
2860
3752
|
var init_patterns = __esm({
|
|
2861
3753
|
"src/radiant/core/patterns.ts"() {
|
|
2862
3754
|
"use strict";
|
|
3755
|
+
init_compress();
|
|
2863
3756
|
}
|
|
2864
3757
|
});
|
|
2865
3758
|
|
|
@@ -2877,30 +3770,16 @@ Window: last ${input.windowDays} days \xB7 ${input.eventCount} events
|
|
|
2877
3770
|
Lens: ${input.lens.name}`
|
|
2878
3771
|
);
|
|
2879
3772
|
if (input.patterns.length > 0) {
|
|
2880
|
-
const canonical = input.patterns.filter((p) => p.type === "canonical");
|
|
2881
|
-
const candidates = input.patterns.filter((p) => p.type === "candidate");
|
|
2882
3773
|
let emergentBlock = "EMERGENT\n";
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
emergentBlock += `
|
|
3774
|
+
for (const p of input.patterns) {
|
|
3775
|
+
emergentBlock += `
|
|
2886
3776
|
${p.name}
|
|
2887
3777
|
`;
|
|
2888
|
-
|
|
2889
|
-
`;
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
2892
|
-
if (candidates.length > 0) {
|
|
2893
|
-
emergentBlock += "\n Emergent (candidates \u2014 not yet in worldmodel)\n";
|
|
2894
|
-
for (const p of candidates) {
|
|
2895
|
-
emergentBlock += `
|
|
2896
|
-
${p.name} (candidate)
|
|
3778
|
+
emergentBlock += ` ${p.description}
|
|
2897
3779
|
`;
|
|
2898
|
-
|
|
3780
|
+
if (p.evidence.cited_invariant) {
|
|
3781
|
+
emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
|
|
2899
3782
|
`;
|
|
2900
|
-
if (p.evidence.cited_invariant) {
|
|
2901
|
-
emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
|
|
2902
|
-
`;
|
|
2903
|
-
}
|
|
2904
3783
|
}
|
|
2905
3784
|
}
|
|
2906
3785
|
sections.push(emergentBlock.trimEnd());
|
|
@@ -3119,21 +3998,80 @@ var init_renderer = __esm({
|
|
|
3119
3998
|
async function emergent(input) {
|
|
3120
3999
|
const lens = resolveLens2(input.lensId);
|
|
3121
4000
|
const windowDays = input.windowDays ?? 14;
|
|
4001
|
+
let worldStack;
|
|
4002
|
+
let worldmodelContent = input.worldmodelContent;
|
|
4003
|
+
if (!worldmodelContent || worldmodelContent.trim() === "") {
|
|
4004
|
+
worldStack = discoverWorlds({ explicitWorldsDir: input.worldPath });
|
|
4005
|
+
worldmodelContent = worldStack.combinedContent;
|
|
4006
|
+
}
|
|
3122
4007
|
let statedIntent;
|
|
3123
4008
|
let exocortexContext;
|
|
3124
4009
|
let priorReadContext = "";
|
|
3125
4010
|
if (input.exocortexPath) {
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
4011
|
+
const repoName = input.scope.type === "repo" ? input.scope.repo : void 0;
|
|
4012
|
+
exocortexContext = readExocortex(input.exocortexPath, repoName);
|
|
4013
|
+
const compressed = compressExocortex(exocortexContext);
|
|
4014
|
+
if (compressed) {
|
|
4015
|
+
statedIntent = `## Stated Intent (from exocortex, compressed)
|
|
4016
|
+
|
|
4017
|
+
${compressed}
|
|
4018
|
+
|
|
4019
|
+
Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
4020
|
+
}
|
|
3129
4021
|
const priorReads = loadPriorReads(input.exocortexPath);
|
|
3130
4022
|
if (priorReads.length > 0) {
|
|
3131
|
-
priorReadContext =
|
|
4023
|
+
priorReadContext = compressPriorReads(priorReads);
|
|
3132
4024
|
}
|
|
3133
4025
|
}
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
4026
|
+
let events;
|
|
4027
|
+
let orgRepos;
|
|
4028
|
+
if (input.scope.type === "org") {
|
|
4029
|
+
const orgResult = await fetchGitHubOrgActivity(
|
|
4030
|
+
input.scope,
|
|
4031
|
+
input.githubToken,
|
|
4032
|
+
{ windowDays }
|
|
4033
|
+
);
|
|
4034
|
+
events = orgResult.events;
|
|
4035
|
+
orgRepos = orgResult.repos;
|
|
4036
|
+
} else {
|
|
4037
|
+
events = await fetchGitHubActivity(input.scope, input.githubToken, {
|
|
4038
|
+
windowDays
|
|
4039
|
+
});
|
|
4040
|
+
}
|
|
4041
|
+
let adapterSignals = "";
|
|
4042
|
+
const activeAdapters = ["github"];
|
|
4043
|
+
const discordToken = process.env.DISCORD_TOKEN;
|
|
4044
|
+
const discordGuild = process.env.DISCORD_GUILD_ID;
|
|
4045
|
+
if (discordToken && discordGuild) {
|
|
4046
|
+
try {
|
|
4047
|
+
const discord = await fetchDiscordActivity(discordGuild, discordToken, { windowDays });
|
|
4048
|
+
events.push(...discord.events);
|
|
4049
|
+
adapterSignals += "\n\n" + formatDiscordSignalsForPrompt(discord.signals);
|
|
4050
|
+
activeAdapters.push("discord");
|
|
4051
|
+
} catch {
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
const slackToken = process.env.SLACK_TOKEN;
|
|
4055
|
+
if (slackToken) {
|
|
4056
|
+
try {
|
|
4057
|
+
const slack = await fetchSlackActivity(slackToken, { windowDays });
|
|
4058
|
+
events.push(...slack.events);
|
|
4059
|
+
adapterSignals += "\n\n" + formatSlackSignalsForPrompt(slack.signals);
|
|
4060
|
+
activeAdapters.push("slack");
|
|
4061
|
+
} catch {
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
const notionToken = process.env.NOTION_TOKEN;
|
|
4065
|
+
if (notionToken) {
|
|
4066
|
+
try {
|
|
4067
|
+
const notion = await fetchNotionActivity(notionToken, { windowDays });
|
|
4068
|
+
events.push(...notion.events);
|
|
4069
|
+
adapterSignals += "\n\n" + formatNotionSignalsForPrompt(notion.signals);
|
|
4070
|
+
activeAdapters.push("notion");
|
|
4071
|
+
} catch {
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
3137
4075
|
const classified = classifyEvents(events);
|
|
3138
4076
|
const signals = extractSignals(classified);
|
|
3139
4077
|
const scores = computeScores(signals, input.worldmodelContent !== "");
|
|
@@ -3144,7 +4082,7 @@ async function emergent(input) {
|
|
|
3144
4082
|
lens,
|
|
3145
4083
|
ai: input.ai,
|
|
3146
4084
|
canonicalPatterns: input.canonicalPatterns,
|
|
3147
|
-
statedIntent: statedIntent
|
|
4085
|
+
statedIntent: [statedIntent, adapterSignals, priorReadContext].filter(Boolean).join("\n\n") || void 0
|
|
3148
4086
|
});
|
|
3149
4087
|
const rewrittenPatterns = patterns.map((p) => lens.rewrite(p));
|
|
3150
4088
|
const allDescriptions = rewrittenPatterns.map((p) => p.description).join("\n");
|
|
@@ -3193,7 +4131,9 @@ async function emergent(input) {
|
|
|
3193
4131
|
voiceClean: voiceViolations.length === 0,
|
|
3194
4132
|
signals,
|
|
3195
4133
|
scores,
|
|
3196
|
-
eventCount: events.length
|
|
4134
|
+
eventCount: events.length,
|
|
4135
|
+
activeAdapters,
|
|
4136
|
+
worldStack
|
|
3197
4137
|
};
|
|
3198
4138
|
}
|
|
3199
4139
|
function computeScores(signals, worldmodelLoaded) {
|
|
@@ -3248,8 +4188,13 @@ var init_emergent = __esm({
|
|
|
3248
4188
|
"use strict";
|
|
3249
4189
|
init_lenses();
|
|
3250
4190
|
init_github();
|
|
4191
|
+
init_discord();
|
|
4192
|
+
init_slack();
|
|
4193
|
+
init_notion();
|
|
4194
|
+
init_discovery();
|
|
3251
4195
|
init_exocortex();
|
|
3252
4196
|
init_palace();
|
|
4197
|
+
init_compress();
|
|
3253
4198
|
init_governance();
|
|
3254
4199
|
init_signals();
|
|
3255
4200
|
init_math();
|
|
@@ -3306,22 +4251,22 @@ __export(server_exports, {
|
|
|
3306
4251
|
startRadiantMcp: () => startRadiantMcp
|
|
3307
4252
|
});
|
|
3308
4253
|
function loadWorldmodelContent(worldsPath) {
|
|
3309
|
-
const resolved = (0,
|
|
3310
|
-
if (!(0,
|
|
4254
|
+
const resolved = (0, import_path4.resolve)(worldsPath);
|
|
4255
|
+
if (!(0, import_fs4.existsSync)(resolved)) {
|
|
3311
4256
|
throw new Error(`Worlds path not found: ${resolved}`);
|
|
3312
4257
|
}
|
|
3313
|
-
const stat = (0,
|
|
4258
|
+
const stat = (0, import_fs4.statSync)(resolved);
|
|
3314
4259
|
if (stat.isFile()) {
|
|
3315
|
-
return (0,
|
|
4260
|
+
return (0, import_fs4.readFileSync)(resolved, "utf-8");
|
|
3316
4261
|
}
|
|
3317
4262
|
if (stat.isDirectory()) {
|
|
3318
|
-
const files = (0,
|
|
3319
|
-
(f) => (0,
|
|
4263
|
+
const files = (0, import_fs4.readdirSync)(resolved).filter(
|
|
4264
|
+
(f) => (0, import_path4.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
|
|
3320
4265
|
).sort();
|
|
3321
4266
|
if (files.length === 0) {
|
|
3322
4267
|
throw new Error(`No worldmodel files found in ${resolved}`);
|
|
3323
4268
|
}
|
|
3324
|
-
return files.map((f) => (0,
|
|
4269
|
+
return files.map((f) => (0, import_fs4.readFileSync)((0, import_path4.join)(resolved, f), "utf-8")).join("\n\n---\n\n");
|
|
3325
4270
|
}
|
|
3326
4271
|
throw new Error(`Worlds path is neither a file nor directory: ${resolved}`);
|
|
3327
4272
|
}
|
|
@@ -3340,12 +4285,12 @@ async function startRadiantMcp(args) {
|
|
|
3340
4285
|
const server = new RadiantMcpServer({ worldsPath, lensId, model });
|
|
3341
4286
|
await server.start();
|
|
3342
4287
|
}
|
|
3343
|
-
var
|
|
4288
|
+
var import_fs4, import_path4, TOOLS, RadiantMcpServer;
|
|
3344
4289
|
var init_server = __esm({
|
|
3345
4290
|
"src/radiant/mcp/server.ts"() {
|
|
3346
4291
|
"use strict";
|
|
3347
|
-
|
|
3348
|
-
|
|
4292
|
+
import_fs4 = require("fs");
|
|
4293
|
+
import_path4 = require("path");
|
|
3349
4294
|
init_think();
|
|
3350
4295
|
init_emergent();
|
|
3351
4296
|
init_ai();
|
|
@@ -3576,8 +4521,8 @@ __export(radiant_exports, {
|
|
|
3576
4521
|
main: () => main
|
|
3577
4522
|
});
|
|
3578
4523
|
module.exports = __toCommonJS(radiant_exports);
|
|
3579
|
-
var
|
|
3580
|
-
var
|
|
4524
|
+
var import_fs5 = require("fs");
|
|
4525
|
+
var import_path5 = require("path");
|
|
3581
4526
|
init_think();
|
|
3582
4527
|
init_emergent();
|
|
3583
4528
|
init_ai();
|
|
@@ -3624,6 +4569,8 @@ function parseArgs(argv) {
|
|
|
3624
4569
|
query: void 0,
|
|
3625
4570
|
model: void 0,
|
|
3626
4571
|
exocortex: void 0,
|
|
4572
|
+
teamExocortex: void 0,
|
|
4573
|
+
view: void 0,
|
|
3627
4574
|
json: false,
|
|
3628
4575
|
help: false,
|
|
3629
4576
|
rest: []
|
|
@@ -3651,6 +4598,12 @@ function parseArgs(argv) {
|
|
|
3651
4598
|
case "--exocortex":
|
|
3652
4599
|
result.exocortex = argv[++i];
|
|
3653
4600
|
break;
|
|
4601
|
+
case "--team-exocortex":
|
|
4602
|
+
result.teamExocortex = argv[++i];
|
|
4603
|
+
break;
|
|
4604
|
+
case "--view":
|
|
4605
|
+
result.view = argv[++i];
|
|
4606
|
+
break;
|
|
3654
4607
|
case "--json":
|
|
3655
4608
|
result.json = true;
|
|
3656
4609
|
break;
|
|
@@ -3667,17 +4620,17 @@ function parseArgs(argv) {
|
|
|
3667
4620
|
return result;
|
|
3668
4621
|
}
|
|
3669
4622
|
function loadWorldmodelContent2(worldsPath) {
|
|
3670
|
-
const resolved = (0,
|
|
3671
|
-
if (!(0,
|
|
4623
|
+
const resolved = (0, import_path5.resolve)(worldsPath);
|
|
4624
|
+
if (!(0, import_fs5.existsSync)(resolved)) {
|
|
3672
4625
|
throw new Error(`Worlds path not found: ${resolved}`);
|
|
3673
4626
|
}
|
|
3674
|
-
const stat = (0,
|
|
4627
|
+
const stat = (0, import_fs5.statSync)(resolved);
|
|
3675
4628
|
if (stat.isFile()) {
|
|
3676
|
-
return (0,
|
|
4629
|
+
return (0, import_fs5.readFileSync)(resolved, "utf-8");
|
|
3677
4630
|
}
|
|
3678
4631
|
if (stat.isDirectory()) {
|
|
3679
|
-
const files = (0,
|
|
3680
|
-
(f) => (0,
|
|
4632
|
+
const files = (0, import_fs5.readdirSync)(resolved).filter(
|
|
4633
|
+
(f) => (0, import_path5.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
|
|
3681
4634
|
).sort();
|
|
3682
4635
|
if (files.length === 0) {
|
|
3683
4636
|
throw new Error(
|
|
@@ -3685,7 +4638,7 @@ function loadWorldmodelContent2(worldsPath) {
|
|
|
3685
4638
|
);
|
|
3686
4639
|
}
|
|
3687
4640
|
return files.map((f) => {
|
|
3688
|
-
const content = (0,
|
|
4641
|
+
const content = (0, import_fs5.readFileSync)((0, import_path5.join)(resolved, f), "utf-8");
|
|
3689
4642
|
return `<!-- worldmodel: ${f} -->
|
|
3690
4643
|
${content}`;
|
|
3691
4644
|
}).join("\n\n---\n\n");
|
|
@@ -3724,7 +4677,7 @@ ${DIM}Set it to your Anthropic API key to use Radiant's AI features.${RESET}
|
|
|
3724
4677
|
query = args.rest.join(" ");
|
|
3725
4678
|
}
|
|
3726
4679
|
if (!query && !process.stdin.isTTY) {
|
|
3727
|
-
query = (0,
|
|
4680
|
+
query = (0, import_fs5.readFileSync)(0, "utf-8").trim();
|
|
3728
4681
|
}
|
|
3729
4682
|
if (!query) {
|
|
3730
4683
|
process.stderr.write(
|
|
@@ -3792,7 +4745,7 @@ async function cmdEmergent(args) {
|
|
|
3792
4745
|
);
|
|
3793
4746
|
process.exit(1);
|
|
3794
4747
|
}
|
|
3795
|
-
const scope =
|
|
4748
|
+
const scope = parseScope(scopeStr);
|
|
3796
4749
|
const lensId = args.lens ?? process.env.RADIANT_LENS;
|
|
3797
4750
|
if (!lensId) {
|
|
3798
4751
|
process.stderr.write(
|
|
@@ -3830,6 +4783,15 @@ ${DIM}Set it to a GitHub PAT with repo read access.${RESET}
|
|
|
3830
4783
|
const worldmodelContent = loadWorldmodelContent2(worldsPath);
|
|
3831
4784
|
const model = args.model ?? process.env.RADIANT_MODEL;
|
|
3832
4785
|
const ai = createAnthropicAI(anthropicKey, model || void 0);
|
|
4786
|
+
const view = args.view ?? process.env.RADIANT_VIEW ?? "community";
|
|
4787
|
+
const validViews = ["community", "team", "full"];
|
|
4788
|
+
if (!validViews.includes(view)) {
|
|
4789
|
+
process.stderr.write(
|
|
4790
|
+
`${RED}Error:${RESET} --view must be community, team, or full. Got "${view}".
|
|
4791
|
+
`
|
|
4792
|
+
);
|
|
4793
|
+
process.exit(1);
|
|
4794
|
+
}
|
|
3833
4795
|
const exocortexPath = args.exocortex ?? process.env.RADIANT_EXOCORTEX;
|
|
3834
4796
|
let exocortexStatus = "not loaded";
|
|
3835
4797
|
if (exocortexPath) {
|
|
@@ -3837,7 +4799,8 @@ ${DIM}Set it to a GitHub PAT with repo read access.${RESET}
|
|
|
3837
4799
|
exocortexStatus = summarizeExocortex(ctx);
|
|
3838
4800
|
}
|
|
3839
4801
|
process.stderr.write(
|
|
3840
|
-
`${DIM}Scope: ${scope.owner
|
|
4802
|
+
`${DIM}Scope: ${scope.type === "org" ? scope.owner + " (entire org)" : scope.owner + "/" + scope.repo}${RESET}
|
|
4803
|
+
${DIM}View: ${view}${RESET}
|
|
3841
4804
|
${DIM}Lens: ${lensId}${RESET}
|
|
3842
4805
|
${DIM}Model: ${model ?? "claude-sonnet-4-20250514 (default)"}${RESET}
|
|
3843
4806
|
${DIM}ExoCortex: ${exocortexStatus}${RESET}
|