@neuroverseos/governance 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 sections = [];
487
- sections.push(
488
- `## Worldmodel
489
-
490
- You are operating inside a governed environment. The worldmodel below
491
- defines the invariants, signals, decision priorities, and behavioral
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}
506
-
507
- ### Evaluation questions to reason through
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)
508
908
 
509
- ${questionsBlock}
909
+ ${compressedWorld}`,
910
+ // Section 2: Analytical frame (evaluation questions + rubric)
911
+ `## How to Think
510
912
 
511
- ### Overlap emergent states
913
+ ${cl.scoringRubric}
512
914
 
513
- ${overlapsBlock}
915
+ Questions:
916
+ ${cl.evaluationQuestions}
514
917
 
515
- ### Center identity
918
+ Overlaps: ${overlapsBlock}
919
+ Center: ${lens.primary_frame.center_identity}
516
920
 
517
- When all dimensions integrate fully: **${frame.center_identity}**. Surface this sparingly \u2014 only when the integration is genuinely complete.`
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
- ### Vocabulary
542
-
543
- Proper nouns (use literally): ${vocabProperNouns}
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 any of these phrases in your response. If you catch yourself
561
- reaching for one, rephrase in direct, active, specific language instead.
562
-
563
- ${forbiddenBlock}
935
+ Do NOT use: ${cl.forbiddenPhrases}
564
936
 
565
- If your response would violate a worldmodel invariant, state the conflict
566
- explicitly and propose an alternative that honors the invariant.`
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
 
@@ -890,16 +1261,491 @@ var init_github = __esm({
890
1261
  }
891
1262
  });
892
1263
 
893
- // src/radiant/adapters/exocortex.ts
894
- function readExocortex(dirPath) {
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) {
895
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);
896
1742
  let filesLoaded = 0;
897
1743
  function tryRead(...paths) {
898
1744
  for (const p of paths) {
899
- const full = (0, import_path.join)(dir, p);
900
- if ((0, import_fs.existsSync)(full)) {
1745
+ const full = (0, import_path2.join)(dir, p);
1746
+ if ((0, import_fs2.existsSync)(full)) {
901
1747
  try {
902
- const content = (0, import_fs.readFileSync)(full, "utf-8").trim();
1748
+ const content = (0, import_fs2.readFileSync)(full, "utf-8").trim();
903
1749
  if (content) {
904
1750
  filesLoaded++;
905
1751
  return content;
@@ -910,55 +1756,65 @@ function readExocortex(dirPath) {
910
1756
  }
911
1757
  return null;
912
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
+ }
913
1796
  const ctx = {
914
- attention: tryRead("attention.md"),
915
- goals: tryRead("goals.md"),
916
- identity: tryRead("identity.md"),
917
- sprint: tryRead("sprint.md", "src/sprint.md"),
918
- organization: tryRead("org/organization.md", "org/src/organization.md"),
919
- methods: tryRead("org/methods.md", "org/src/methods.md"),
1797
+ attention,
1798
+ goals,
1799
+ identity,
1800
+ sprint,
1801
+ organization,
1802
+ methods,
920
1803
  source: dir,
921
1804
  filesLoaded
922
1805
  };
923
- return ctx;
924
- }
925
- function formatExocortexForPrompt(ctx) {
926
- if (ctx.filesLoaded === 0) return "";
927
- const sections = [];
928
- sections.push(
929
- "## 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."
930
- );
931
- if (ctx.attention) {
932
- sections.push(`### Current attention
1806
+ if (projectContext && ctx.sprint) {
1807
+ ctx.sprint = `${ctx.sprint}
933
1808
 
934
- ${ctx.attention}`);
1809
+ ---
1810
+ Project roadmap:
1811
+ ${projectContext}`;
1812
+ } else if (projectContext) {
1813
+ ctx.sprint = `Project roadmap:
1814
+ ${projectContext}`;
1815
+ ctx.filesLoaded++;
935
1816
  }
936
- if (ctx.goals) {
937
- sections.push(`### Goals
938
-
939
- ${ctx.goals}`);
940
- }
941
- if (ctx.sprint) {
942
- sections.push(`### Sprint focus
943
-
944
- ${ctx.sprint}`);
945
- }
946
- if (ctx.identity) {
947
- sections.push(`### Identity and values
948
-
949
- ${ctx.identity}`);
950
- }
951
- if (ctx.organization) {
952
- sections.push(`### Organization
953
-
954
- ${ctx.organization}`);
955
- }
956
- if (ctx.methods) {
957
- sections.push(`### Methods
958
-
959
- ${ctx.methods}`);
960
- }
961
- return sections.join("\n\n");
1817
+ return ctx;
962
1818
  }
963
1819
  function summarizeExocortex(ctx) {
964
1820
  if (ctx.filesLoaded === 0) return "no exocortex files found";
@@ -971,33 +1827,33 @@ function summarizeExocortex(ctx) {
971
1827
  if (ctx.methods) loaded.push("methods");
972
1828
  return `${loaded.join(", ")} (${ctx.filesLoaded} files)`;
973
1829
  }
974
- var import_fs, import_path;
1830
+ var import_fs2, import_path2;
975
1831
  var init_exocortex = __esm({
976
1832
  "src/radiant/adapters/exocortex.ts"() {
977
1833
  "use strict";
978
- import_fs = require("fs");
979
- import_path = require("path");
1834
+ import_fs2 = require("fs");
1835
+ import_path2 = require("path");
980
1836
  }
981
1837
  });
982
1838
 
983
1839
  // src/radiant/memory/palace.ts
984
1840
  function writeRead(exocortexDir, frontmatter, text) {
985
- const dir = (0, import_path2.resolve)(exocortexDir, "radiant", "reads");
986
- (0, import_fs2.mkdirSync)(dir, { recursive: true });
1841
+ const dir = (0, import_path3.resolve)(exocortexDir, "radiant", "reads");
1842
+ (0, import_fs3.mkdirSync)(dir, { recursive: true });
987
1843
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
988
1844
  const filename = `${date}.md`;
989
- const filepath = (0, import_path2.join)(dir, filename);
1845
+ const filepath = (0, import_path3.join)(dir, filename);
990
1846
  const content = `${frontmatter}
991
1847
 
992
1848
  ${text}
993
1849
  `;
994
- (0, import_fs2.writeFileSync)(filepath, content, "utf-8");
1850
+ (0, import_fs3.writeFileSync)(filepath, content, "utf-8");
995
1851
  return filepath;
996
1852
  }
997
1853
  function updateKnowledge(exocortexDir, persistence, options) {
998
- const dir = (0, import_path2.resolve)(exocortexDir, "radiant");
999
- (0, import_fs2.mkdirSync)(dir, { recursive: true });
1000
- const filepath = (0, import_path2.join)(dir, "knowledge.md");
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");
1001
1857
  const totalReads = options?.totalReads ?? 0;
1002
1858
  const existingUntriggered = loadUntriggeredCounts(filepath);
1003
1859
  const lines = [
@@ -1084,14 +1940,14 @@ function updateKnowledge(exocortexDir, persistence, options) {
1084
1940
  lines.push(`${name}=${count}`);
1085
1941
  }
1086
1942
  lines.push("-->");
1087
- (0, import_fs2.writeFileSync)(filepath, lines.join("\n"), "utf-8");
1943
+ (0, import_fs3.writeFileSync)(filepath, lines.join("\n"), "utf-8");
1088
1944
  return filepath;
1089
1945
  }
1090
1946
  function loadUntriggeredCounts(filepath) {
1091
1947
  const counts = /* @__PURE__ */ new Map();
1092
- if (!(0, import_fs2.existsSync)(filepath)) return counts;
1948
+ if (!(0, import_fs3.existsSync)(filepath)) return counts;
1093
1949
  try {
1094
- const content = (0, import_fs2.readFileSync)(filepath, "utf-8");
1950
+ const content = (0, import_fs3.readFileSync)(filepath, "utf-8");
1095
1951
  const match = content.match(
1096
1952
  /<!-- untriggered_counts[\s\S]*?-->/
1097
1953
  );
@@ -1109,13 +1965,13 @@ function loadUntriggeredCounts(filepath) {
1109
1965
  return counts;
1110
1966
  }
1111
1967
  function loadPriorReads(exocortexDir) {
1112
- const dir = (0, import_path2.resolve)(exocortexDir, "radiant", "reads");
1113
- if (!(0, import_fs2.existsSync)(dir)) return [];
1114
- const files = (0, import_fs2.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
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();
1115
1971
  const reads = [];
1116
1972
  for (const filename of files) {
1117
- const filepath = (0, import_path2.join)(dir, filename);
1118
- const content = (0, import_fs2.readFileSync)(filepath, "utf-8");
1973
+ const filepath = (0, import_path3.join)(dir, filename);
1974
+ const content = (0, import_fs3.readFileSync)(filepath, "utf-8");
1119
1975
  const date = filename.replace(".md", "");
1120
1976
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
1121
1977
  const frontmatter = fmMatch ? fmMatch[1] : "";
@@ -1149,33 +2005,12 @@ function computePersistence(priorReads, currentPatternNames) {
1149
2005
  dates: dates.sort()
1150
2006
  })).sort((a, b) => b.occurrences - a.occurrences);
1151
2007
  }
1152
- function formatPriorReadsForPrompt(priorReads) {
1153
- if (priorReads.length === 0) return "";
1154
- const lines = [
1155
- "## Prior Radiant reads (history)",
1156
- "",
1157
- `Radiant has run ${priorReads.length} time${priorReads.length > 1 ? "s" : ""} before on this scope.`,
1158
- "If you see patterns that appeared in prior reads, note their persistence.",
1159
- "Patterns that recur across 3+ reads are strong candidates for declaration in the strategy file.",
1160
- ""
1161
- ];
1162
- for (const read of priorReads.slice(-4)) {
1163
- lines.push(`### Read from ${read.date}`);
1164
- if (read.patternNames.length > 0) {
1165
- lines.push(`Patterns observed: ${read.patternNames.join(", ")}`);
1166
- } else {
1167
- lines.push("No patterns extracted from frontmatter.");
1168
- }
1169
- lines.push("");
1170
- }
1171
- return lines.join("\n");
1172
- }
1173
- var import_fs2, import_path2;
2008
+ var import_fs3, import_path3;
1174
2009
  var init_palace = __esm({
1175
2010
  "src/radiant/memory/palace.ts"() {
1176
2011
  "use strict";
1177
- import_fs2 = require("fs");
1178
- import_path2 = require("path");
2012
+ import_fs3 = require("fs");
2013
+ import_path3 = require("path");
1179
2014
  }
1180
2015
  });
1181
2016
 
@@ -2284,10 +3119,10 @@ var init_guard_engine = __esm({
2284
3119
  // src/loader/world-loader.ts
2285
3120
  async function loadWorldFromDirectory(dirPath) {
2286
3121
  const { readFile } = await import("fs/promises");
2287
- const { join: join5 } = await import("path");
2288
- const { readdirSync: readdirSync5 } = await import("fs");
3122
+ const { join: join6 } = await import("path");
3123
+ const { readdirSync: readdirSync6 } = await import("fs");
2289
3124
  async function readJson(filename) {
2290
- const filePath = join5(dirPath, filename);
3125
+ const filePath = join6(dirPath, filename);
2291
3126
  try {
2292
3127
  const content = await readFile(filePath, "utf-8");
2293
3128
  return JSON.parse(content);
@@ -2317,11 +3152,11 @@ async function loadWorldFromDirectory(dirPath) {
2317
3152
  const metadataJson = await readJson("metadata.json");
2318
3153
  const rules = [];
2319
3154
  try {
2320
- const rulesDir = join5(dirPath, "rules");
2321
- const ruleFiles = readdirSync5(rulesDir).filter((f) => f.endsWith(".json")).sort();
3155
+ const rulesDir = join6(dirPath, "rules");
3156
+ const ruleFiles = readdirSync6(rulesDir).filter((f) => f.endsWith(".json")).sort();
2322
3157
  for (const file of ruleFiles) {
2323
3158
  try {
2324
- const content = await readFile(join5(rulesDir, file), "utf-8");
3159
+ const content = await readFile(join6(rulesDir, file), "utf-8");
2325
3160
  rules.push(JSON.parse(content));
2326
3161
  } catch (err) {
2327
3162
  process.stderr.write(
@@ -2728,15 +3563,17 @@ function buildInterpretationPrompt(input) {
2728
3563
  const eventSample = formatEventSample(input.events, 30);
2729
3564
  const canonicalList = (input.canonicalPatterns ?? []).length > 0 ? `Patterns the organization has already named (use these names if you see them):
2730
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);
2731
3568
  const frame = input.lens.primary_frame;
2732
3569
  const evalQuestions = frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n");
2733
- const forbiddenList = input.lens.forbidden_phrases.map((p) => `- "${p}"`).join("\n");
2734
- const jargonTable = Object.entries(input.lens.vocabulary.jargon_translations).map(([internal, plain]) => ` "${internal}" \u2192 "${plain}"`).join("\n");
3570
+ const forbiddenList = cl.forbiddenPhrases;
3571
+ const jargonTable = cl.jargonTranslations;
2735
3572
  return `You are a behavioral intelligence system reading team activity and producing a read for the reader who needs to act on it.
2736
3573
 
2737
- ## Context the reader has loaded
3574
+ ## Worldmodel (compressed)
2738
3575
 
2739
- ${input.worldmodelContent}
3576
+ ${compressedWorld}
2740
3577
 
2741
3578
  ## What happened this window
2742
3579
 
@@ -2915,6 +3752,7 @@ function isPatternLike(x) {
2915
3752
  var init_patterns = __esm({
2916
3753
  "src/radiant/core/patterns.ts"() {
2917
3754
  "use strict";
3755
+ init_compress();
2918
3756
  }
2919
3757
  });
2920
3758
 
@@ -2932,30 +3770,16 @@ Window: last ${input.windowDays} days \xB7 ${input.eventCount} events
2932
3770
  Lens: ${input.lens.name}`
2933
3771
  );
2934
3772
  if (input.patterns.length > 0) {
2935
- const canonical = input.patterns.filter((p) => p.type === "canonical");
2936
- const candidates = input.patterns.filter((p) => p.type === "candidate");
2937
3773
  let emergentBlock = "EMERGENT\n";
2938
- if (canonical.length > 0) {
2939
- for (const p of canonical) {
2940
- emergentBlock += `
3774
+ for (const p of input.patterns) {
3775
+ emergentBlock += `
2941
3776
  ${p.name}
2942
3777
  `;
2943
- emergentBlock += ` ${p.description}
3778
+ emergentBlock += ` ${p.description}
2944
3779
  `;
2945
- }
2946
- }
2947
- if (candidates.length > 0) {
2948
- emergentBlock += "\n Emergent (candidates \u2014 not yet in worldmodel)\n";
2949
- for (const p of candidates) {
2950
- emergentBlock += `
2951
- ${p.name} (candidate)
2952
- `;
2953
- emergentBlock += ` ${p.description}
3780
+ if (p.evidence.cited_invariant) {
3781
+ emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
2954
3782
  `;
2955
- if (p.evidence.cited_invariant) {
2956
- emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
2957
- `;
2958
- }
2959
3783
  }
2960
3784
  }
2961
3785
  sections.push(emergentBlock.trimEnd());
@@ -3174,16 +3998,29 @@ var init_renderer = __esm({
3174
3998
  async function emergent(input) {
3175
3999
  const lens = resolveLens2(input.lensId);
3176
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
+ }
3177
4007
  let statedIntent;
3178
4008
  let exocortexContext;
3179
4009
  let priorReadContext = "";
3180
4010
  if (input.exocortexPath) {
3181
- exocortexContext = readExocortex(input.exocortexPath);
3182
- const formatted = formatExocortexForPrompt(exocortexContext);
3183
- if (formatted) statedIntent = formatted;
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
+ }
3184
4021
  const priorReads = loadPriorReads(input.exocortexPath);
3185
4022
  if (priorReads.length > 0) {
3186
- priorReadContext = formatPriorReadsForPrompt(priorReads);
4023
+ priorReadContext = compressPriorReads(priorReads);
3187
4024
  }
3188
4025
  }
3189
4026
  let events;
@@ -3201,6 +4038,40 @@ async function emergent(input) {
3201
4038
  windowDays
3202
4039
  });
3203
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));
3204
4075
  const classified = classifyEvents(events);
3205
4076
  const signals = extractSignals(classified);
3206
4077
  const scores = computeScores(signals, input.worldmodelContent !== "");
@@ -3211,7 +4082,7 @@ async function emergent(input) {
3211
4082
  lens,
3212
4083
  ai: input.ai,
3213
4084
  canonicalPatterns: input.canonicalPatterns,
3214
- statedIntent: statedIntent ? statedIntent + (priorReadContext ? "\n\n" + priorReadContext : "") : priorReadContext || void 0
4085
+ statedIntent: [statedIntent, adapterSignals, priorReadContext].filter(Boolean).join("\n\n") || void 0
3215
4086
  });
3216
4087
  const rewrittenPatterns = patterns.map((p) => lens.rewrite(p));
3217
4088
  const allDescriptions = rewrittenPatterns.map((p) => p.description).join("\n");
@@ -3260,7 +4131,9 @@ async function emergent(input) {
3260
4131
  voiceClean: voiceViolations.length === 0,
3261
4132
  signals,
3262
4133
  scores,
3263
- eventCount: events.length
4134
+ eventCount: events.length,
4135
+ activeAdapters,
4136
+ worldStack
3264
4137
  };
3265
4138
  }
3266
4139
  function computeScores(signals, worldmodelLoaded) {
@@ -3315,8 +4188,13 @@ var init_emergent = __esm({
3315
4188
  "use strict";
3316
4189
  init_lenses();
3317
4190
  init_github();
4191
+ init_discord();
4192
+ init_slack();
4193
+ init_notion();
4194
+ init_discovery();
3318
4195
  init_exocortex();
3319
4196
  init_palace();
4197
+ init_compress();
3320
4198
  init_governance();
3321
4199
  init_signals();
3322
4200
  init_math();
@@ -3373,22 +4251,22 @@ __export(server_exports, {
3373
4251
  startRadiantMcp: () => startRadiantMcp
3374
4252
  });
3375
4253
  function loadWorldmodelContent(worldsPath) {
3376
- const resolved = (0, import_path3.resolve)(worldsPath);
3377
- if (!(0, import_fs3.existsSync)(resolved)) {
4254
+ const resolved = (0, import_path4.resolve)(worldsPath);
4255
+ if (!(0, import_fs4.existsSync)(resolved)) {
3378
4256
  throw new Error(`Worlds path not found: ${resolved}`);
3379
4257
  }
3380
- const stat = (0, import_fs3.statSync)(resolved);
4258
+ const stat = (0, import_fs4.statSync)(resolved);
3381
4259
  if (stat.isFile()) {
3382
- return (0, import_fs3.readFileSync)(resolved, "utf-8");
4260
+ return (0, import_fs4.readFileSync)(resolved, "utf-8");
3383
4261
  }
3384
4262
  if (stat.isDirectory()) {
3385
- const files = (0, import_fs3.readdirSync)(resolved).filter(
3386
- (f) => (0, import_path3.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
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"))
3387
4265
  ).sort();
3388
4266
  if (files.length === 0) {
3389
4267
  throw new Error(`No worldmodel files found in ${resolved}`);
3390
4268
  }
3391
- return files.map((f) => (0, import_fs3.readFileSync)((0, import_path3.join)(resolved, f), "utf-8")).join("\n\n---\n\n");
4269
+ return files.map((f) => (0, import_fs4.readFileSync)((0, import_path4.join)(resolved, f), "utf-8")).join("\n\n---\n\n");
3392
4270
  }
3393
4271
  throw new Error(`Worlds path is neither a file nor directory: ${resolved}`);
3394
4272
  }
@@ -3407,12 +4285,12 @@ async function startRadiantMcp(args) {
3407
4285
  const server = new RadiantMcpServer({ worldsPath, lensId, model });
3408
4286
  await server.start();
3409
4287
  }
3410
- var import_fs3, import_path3, TOOLS, RadiantMcpServer;
4288
+ var import_fs4, import_path4, TOOLS, RadiantMcpServer;
3411
4289
  var init_server = __esm({
3412
4290
  "src/radiant/mcp/server.ts"() {
3413
4291
  "use strict";
3414
- import_fs3 = require("fs");
3415
- import_path3 = require("path");
4292
+ import_fs4 = require("fs");
4293
+ import_path4 = require("path");
3416
4294
  init_think();
3417
4295
  init_emergent();
3418
4296
  init_ai();
@@ -3643,8 +4521,8 @@ __export(radiant_exports, {
3643
4521
  main: () => main
3644
4522
  });
3645
4523
  module.exports = __toCommonJS(radiant_exports);
3646
- var import_fs4 = require("fs");
3647
- var import_path4 = require("path");
4524
+ var import_fs5 = require("fs");
4525
+ var import_path5 = require("path");
3648
4526
  init_think();
3649
4527
  init_emergent();
3650
4528
  init_ai();
@@ -3742,17 +4620,17 @@ function parseArgs(argv) {
3742
4620
  return result;
3743
4621
  }
3744
4622
  function loadWorldmodelContent2(worldsPath) {
3745
- const resolved = (0, import_path4.resolve)(worldsPath);
3746
- if (!(0, import_fs4.existsSync)(resolved)) {
4623
+ const resolved = (0, import_path5.resolve)(worldsPath);
4624
+ if (!(0, import_fs5.existsSync)(resolved)) {
3747
4625
  throw new Error(`Worlds path not found: ${resolved}`);
3748
4626
  }
3749
- const stat = (0, import_fs4.statSync)(resolved);
4627
+ const stat = (0, import_fs5.statSync)(resolved);
3750
4628
  if (stat.isFile()) {
3751
- return (0, import_fs4.readFileSync)(resolved, "utf-8");
4629
+ return (0, import_fs5.readFileSync)(resolved, "utf-8");
3752
4630
  }
3753
4631
  if (stat.isDirectory()) {
3754
- const files = (0, import_fs4.readdirSync)(resolved).filter(
3755
- (f) => (0, import_path4.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
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"))
3756
4634
  ).sort();
3757
4635
  if (files.length === 0) {
3758
4636
  throw new Error(
@@ -3760,7 +4638,7 @@ function loadWorldmodelContent2(worldsPath) {
3760
4638
  );
3761
4639
  }
3762
4640
  return files.map((f) => {
3763
- const content = (0, import_fs4.readFileSync)((0, import_path4.join)(resolved, f), "utf-8");
4641
+ const content = (0, import_fs5.readFileSync)((0, import_path5.join)(resolved, f), "utf-8");
3764
4642
  return `<!-- worldmodel: ${f} -->
3765
4643
  ${content}`;
3766
4644
  }).join("\n\n---\n\n");
@@ -3799,7 +4677,7 @@ ${DIM}Set it to your Anthropic API key to use Radiant's AI features.${RESET}
3799
4677
  query = args.rest.join(" ");
3800
4678
  }
3801
4679
  if (!query && !process.stdin.isTTY) {
3802
- query = (0, import_fs4.readFileSync)(0, "utf-8").trim();
4680
+ query = (0, import_fs5.readFileSync)(0, "utf-8").trim();
3803
4681
  }
3804
4682
  if (!query) {
3805
4683
  process.stderr.write(