@neuroverseos/governance 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -0
- package/README.md +180 -10
- package/dist/{chunk-MC6O5GV5.js → chunk-3ZWU7C43.js} +1056 -135
- package/dist/{chunk-VGFDMPVB.js → chunk-TCGGED4G.js} +283 -1
- package/dist/cli/neuroverse.cjs +2000 -460
- package/dist/cli/radiant.cjs +1452 -237
- package/dist/cli/radiant.js +62 -24
- package/dist/cli/worldmodel.cjs +1157 -823
- package/dist/cli/worldmodel.js +116 -1
- package/dist/{lenses-K5FVSALR.js → lenses-XDWK6ZKI.js} +5 -3
- package/dist/radiant/index.cjs +953 -130
- package/dist/radiant/index.d.cts +271 -10
- package/dist/radiant/index.d.ts +271 -10
- package/dist/radiant/index.js +41 -397
- package/dist/{server-DFNY5N5A.js → server-JKUBUK5H.js} +2 -2
- package/dist/worldmodel-create-5SWHVNMQ.js +195 -0
- package/examples/radiant-weekly-workflow.yml +81 -0
- package/package.json +2 -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 + agency + 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
|
+
"agency",
|
|
492
|
+
"integration"
|
|
493
|
+
],
|
|
494
|
+
overlaps: [
|
|
495
|
+
{
|
|
496
|
+
domains: ["stewardship", "agency"],
|
|
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: ["agency", "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
|
+
"agency": [
|
|
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
|
+
"Agency",
|
|
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: "Agency 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, Agency, 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
|
+
"agency 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
|
+
// Agency 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
|
+
"Agency 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: "src/radiant/examples/neuroverse-base/neuroverseos-sovereign-conduit.worldmodel.md",
|
|
717
|
+
title: "The Sovereign Conduit Worldmodel",
|
|
718
|
+
exhibits: ["stewardship", "agency", "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), Agency (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}
|
|
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
|
-
${
|
|
909
|
+
${compressedWorld}`,
|
|
910
|
+
// Section 2: Analytical frame (evaluation questions + rubric)
|
|
911
|
+
`## How to Think
|
|
510
912
|
|
|
511
|
-
|
|
913
|
+
${cl.scoringRubric}
|
|
512
914
|
|
|
513
|
-
|
|
915
|
+
Questions:
|
|
916
|
+
${cl.evaluationQuestions}
|
|
514
917
|
|
|
515
|
-
|
|
918
|
+
Overlaps: ${overlapsBlock}
|
|
919
|
+
Center: ${lens.primary_frame.center_identity}
|
|
516
920
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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.
|
|
935
|
+
Do NOT use: ${cl.forbiddenPhrases}
|
|
562
936
|
|
|
563
|
-
|
|
564
|
-
|
|
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,791 @@ var init_github = __esm({
|
|
|
890
1261
|
}
|
|
891
1262
|
});
|
|
892
1263
|
|
|
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/git-remote.ts
|
|
1674
|
+
function resolveGitConfigPath(repoDir) {
|
|
1675
|
+
const dotGit = (0, import_path.join)(repoDir, ".git");
|
|
1676
|
+
if (!(0, import_fs.existsSync)(dotGit)) return null;
|
|
1677
|
+
try {
|
|
1678
|
+
const stat = (0, import_fs.statSync)(dotGit);
|
|
1679
|
+
if (stat.isDirectory()) {
|
|
1680
|
+
return (0, import_path.join)(dotGit, "config");
|
|
1681
|
+
}
|
|
1682
|
+
if (stat.isFile()) {
|
|
1683
|
+
const content = (0, import_fs.readFileSync)(dotGit, "utf-8");
|
|
1684
|
+
const match = /^gitdir:\s*(.+)$/m.exec(content);
|
|
1685
|
+
if (!match) return null;
|
|
1686
|
+
const gitDir = (0, import_path.resolve)(repoDir, match[1].trim());
|
|
1687
|
+
const configPath = (0, import_path.join)(gitDir, "config");
|
|
1688
|
+
return (0, import_fs.existsSync)(configPath) ? configPath : null;
|
|
1689
|
+
}
|
|
1690
|
+
} catch {
|
|
1691
|
+
return null;
|
|
1692
|
+
}
|
|
1693
|
+
return null;
|
|
1694
|
+
}
|
|
1695
|
+
function readOriginRemote(repoDir) {
|
|
1696
|
+
const configPath = resolveGitConfigPath(repoDir);
|
|
1697
|
+
if (!configPath) return null;
|
|
1698
|
+
try {
|
|
1699
|
+
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
1700
|
+
const sectionRe = /\[remote "origin"\]\s*\n((?:(?!\[)[^\n]*\n?)*)/;
|
|
1701
|
+
const section = sectionRe.exec(raw);
|
|
1702
|
+
if (!section) return null;
|
|
1703
|
+
const urlRe = /^\s*url\s*=\s*(.+?)\s*$/m;
|
|
1704
|
+
const url = urlRe.exec(section[1]);
|
|
1705
|
+
return url ? url[1] : null;
|
|
1706
|
+
} catch {
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
function parseRemoteUrl(url) {
|
|
1711
|
+
const trimmed = url.trim();
|
|
1712
|
+
if (!trimmed) return null;
|
|
1713
|
+
const ssh = /^git@([^:]+):([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
1714
|
+
if (ssh) return { host: ssh[1], owner: ssh[2], repo: ssh[3] };
|
|
1715
|
+
const sshProto = /^ssh:\/\/git@([^/]+)\/([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
1716
|
+
if (sshProto) return { host: sshProto[1], owner: sshProto[2], repo: sshProto[3] };
|
|
1717
|
+
const https = /^https?:\/\/(?:[^@/]+@)?([^/]+)\/([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
1718
|
+
if (https) return { host: https[1], owner: https[2], repo: https[3] };
|
|
1719
|
+
return null;
|
|
1720
|
+
}
|
|
1721
|
+
function getRepoOrigin(repoDir) {
|
|
1722
|
+
const url = readOriginRemote(repoDir);
|
|
1723
|
+
if (!url) return null;
|
|
1724
|
+
return parseRemoteUrl(url);
|
|
1725
|
+
}
|
|
1726
|
+
var import_fs, import_path;
|
|
1727
|
+
var init_git_remote = __esm({
|
|
1728
|
+
"src/radiant/core/git-remote.ts"() {
|
|
1729
|
+
"use strict";
|
|
1730
|
+
import_fs = require("fs");
|
|
1731
|
+
import_path = require("path");
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
|
|
1735
|
+
// src/radiant/core/extends.ts
|
|
1736
|
+
function loadExtendsConfig(repoDir) {
|
|
1737
|
+
const configPath = (0, import_path2.join)(repoDir, ".neuroverse", "config.json");
|
|
1738
|
+
if (!(0, import_fs2.existsSync)(configPath)) return null;
|
|
1739
|
+
try {
|
|
1740
|
+
const raw = (0, import_fs2.readFileSync)(configPath, "utf-8");
|
|
1741
|
+
const parsed = JSON.parse(raw);
|
|
1742
|
+
return parsed;
|
|
1743
|
+
} catch {
|
|
1744
|
+
return null;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
function parseExtendsSpec(raw) {
|
|
1748
|
+
const trimmed = raw.trim();
|
|
1749
|
+
if (!trimmed) return null;
|
|
1750
|
+
if (trimmed.startsWith("github:")) {
|
|
1751
|
+
const rest = trimmed.slice("github:".length);
|
|
1752
|
+
const match = /^([^/]+)\/([^@:]+)(?:@([^:]+))?(?::(.+))?$/.exec(rest);
|
|
1753
|
+
if (!match) return null;
|
|
1754
|
+
return {
|
|
1755
|
+
raw: trimmed,
|
|
1756
|
+
kind: "github",
|
|
1757
|
+
owner: match[1],
|
|
1758
|
+
repo: match[2],
|
|
1759
|
+
ref: match[3] ?? "HEAD",
|
|
1760
|
+
subpath: match[4] ?? ""
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("../") || (0, import_path2.isAbsolute)(trimmed)) {
|
|
1764
|
+
return { raw: trimmed, kind: "local", path: trimmed };
|
|
1765
|
+
}
|
|
1766
|
+
return null;
|
|
1767
|
+
}
|
|
1768
|
+
function getCacheDir(spec, baseCacheDir) {
|
|
1769
|
+
const root = baseCacheDir ?? (0, import_path2.join)((0, import_os.homedir)(), ".neuroverse", "cache", "extends");
|
|
1770
|
+
const key = (0, import_crypto.createHash)("sha256").update(spec.raw).digest("hex").slice(0, 16);
|
|
1771
|
+
return (0, import_path2.join)(root, key);
|
|
1772
|
+
}
|
|
1773
|
+
function isCacheFresh(cacheDir, ttlMs) {
|
|
1774
|
+
const stampPath = (0, import_path2.join)(cacheDir, ".neuroverse-fetched");
|
|
1775
|
+
if (!(0, import_fs2.existsSync)(stampPath)) return false;
|
|
1776
|
+
try {
|
|
1777
|
+
const stamp = (0, import_fs2.statSync)(stampPath);
|
|
1778
|
+
return Date.now() - stamp.mtimeMs < ttlMs;
|
|
1779
|
+
} catch {
|
|
1780
|
+
return false;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
function markCacheFresh(cacheDir) {
|
|
1784
|
+
const stampPath = (0, import_path2.join)(cacheDir, ".neuroverse-fetched");
|
|
1785
|
+
try {
|
|
1786
|
+
(0, import_fs2.mkdirSync)(cacheDir, { recursive: true });
|
|
1787
|
+
(0, import_fs2.writeFileSync)(stampPath, (/* @__PURE__ */ new Date()).toISOString());
|
|
1788
|
+
} catch {
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
function resolveExtendsSpec(spec, repoDir, options) {
|
|
1792
|
+
if (spec.kind === "local") {
|
|
1793
|
+
const full = (0, import_path2.isAbsolute)(spec.path) ? spec.path : (0, import_path2.resolve)(repoDir, spec.path);
|
|
1794
|
+
if (!(0, import_fs2.existsSync)(full)) {
|
|
1795
|
+
return { spec, dir: null, warning: `local extends path not found: ${full}` };
|
|
1796
|
+
}
|
|
1797
|
+
return { spec, dir: full };
|
|
1798
|
+
}
|
|
1799
|
+
const cacheRoot = options?.cacheDir;
|
|
1800
|
+
const ttl = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1801
|
+
const cacheDir = getCacheDir(spec, cacheRoot);
|
|
1802
|
+
const fresh = isCacheFresh(cacheDir, ttl);
|
|
1803
|
+
const needsFetch = options?.forceRefresh || !fresh || !(0, import_fs2.existsSync)(cacheDir);
|
|
1804
|
+
if (needsFetch && options?.noFetch) {
|
|
1805
|
+
if ((0, import_fs2.existsSync)(cacheDir) && (0, import_fs2.existsSync)((0, import_path2.join)(cacheDir, ".neuroverse-fetched"))) {
|
|
1806
|
+
return resolveSubpath(spec, cacheDir);
|
|
1807
|
+
}
|
|
1808
|
+
return options?.silentOnMissing ? { spec, dir: null } : { spec, dir: null, warning: `NEUROVERSE_NO_FETCH set and no cache for ${spec.raw}` };
|
|
1809
|
+
}
|
|
1810
|
+
if (needsFetch) {
|
|
1811
|
+
const fetcher = options?.fetcher ?? defaultGitFetcher;
|
|
1812
|
+
try {
|
|
1813
|
+
fetcher(spec, cacheDir);
|
|
1814
|
+
markCacheFresh(cacheDir);
|
|
1815
|
+
} catch (err) {
|
|
1816
|
+
if ((0, import_fs2.existsSync)(cacheDir) && (0, import_fs2.existsSync)((0, import_path2.join)(cacheDir, ".neuroverse-fetched"))) {
|
|
1817
|
+
const result = resolveSubpath(spec, cacheDir);
|
|
1818
|
+
return options?.silentOnMissing ? result : { ...result, warning: `fetch failed for ${spec.raw}, using stale cache: ${err.message}` };
|
|
1819
|
+
}
|
|
1820
|
+
return options?.silentOnMissing ? { spec, dir: null } : { spec, dir: null, warning: `fetch failed for ${spec.raw}: ${err.message}` };
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return resolveSubpath(spec, cacheDir);
|
|
1824
|
+
}
|
|
1825
|
+
function resolveSubpath(spec, cacheDir) {
|
|
1826
|
+
const target = spec.subpath ? (0, import_path2.join)(cacheDir, spec.subpath) : cacheDir;
|
|
1827
|
+
if (!(0, import_fs2.existsSync)(target)) {
|
|
1828
|
+
return { spec, dir: null, warning: `subpath not found in ${spec.raw}: ${spec.subpath}` };
|
|
1829
|
+
}
|
|
1830
|
+
if (!spec.subpath) {
|
|
1831
|
+
const candidates = [
|
|
1832
|
+
(0, import_path2.join)(target, "worlds"),
|
|
1833
|
+
(0, import_path2.join)(target, ".neuroverse", "worlds")
|
|
1834
|
+
];
|
|
1835
|
+
for (const c of candidates) {
|
|
1836
|
+
if ((0, import_fs2.existsSync)(c)) return { spec, dir: c };
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
return { spec, dir: target };
|
|
1840
|
+
}
|
|
1841
|
+
function detectOrgExtendsSpec(repoDir) {
|
|
1842
|
+
const origin = getRepoOrigin(repoDir);
|
|
1843
|
+
if (!origin) return null;
|
|
1844
|
+
if (origin.host !== "github.com") return null;
|
|
1845
|
+
if (origin.repo === "worlds") return null;
|
|
1846
|
+
return {
|
|
1847
|
+
raw: `github:${origin.owner}/worlds`,
|
|
1848
|
+
kind: "github",
|
|
1849
|
+
owner: origin.owner,
|
|
1850
|
+
repo: "worlds",
|
|
1851
|
+
ref: "HEAD",
|
|
1852
|
+
subpath: ""
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
function resolveAllExtends(repoDir, options) {
|
|
1856
|
+
const config = options?.config !== void 0 ? options.config : loadExtendsConfig(repoDir);
|
|
1857
|
+
if (!config?.extends || config.extends.length === 0) return [];
|
|
1858
|
+
const results = [];
|
|
1859
|
+
for (const raw of config.extends) {
|
|
1860
|
+
const spec = parseExtendsSpec(raw);
|
|
1861
|
+
if (!spec) {
|
|
1862
|
+
results.push({
|
|
1863
|
+
spec: { raw, kind: "local" },
|
|
1864
|
+
dir: null,
|
|
1865
|
+
warning: `unparseable extends spec: ${raw}`
|
|
1866
|
+
});
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1869
|
+
results.push(resolveExtendsSpec(spec, repoDir, options));
|
|
1870
|
+
}
|
|
1871
|
+
return results;
|
|
1872
|
+
}
|
|
1873
|
+
var import_fs2, import_path2, import_os, import_crypto, import_child_process, DEFAULT_TTL_MS, defaultGitFetcher;
|
|
1874
|
+
var init_extends = __esm({
|
|
1875
|
+
"src/radiant/core/extends.ts"() {
|
|
1876
|
+
"use strict";
|
|
1877
|
+
import_fs2 = require("fs");
|
|
1878
|
+
import_path2 = require("path");
|
|
1879
|
+
import_os = require("os");
|
|
1880
|
+
import_crypto = require("crypto");
|
|
1881
|
+
import_child_process = require("child_process");
|
|
1882
|
+
init_git_remote();
|
|
1883
|
+
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
1884
|
+
defaultGitFetcher = (spec, destDir) => {
|
|
1885
|
+
if (spec.kind !== "github") return;
|
|
1886
|
+
const url = `https://github.com/${spec.owner}/${spec.repo}.git`;
|
|
1887
|
+
const parent = (0, import_path2.resolve)(destDir, "..");
|
|
1888
|
+
(0, import_fs2.mkdirSync)(parent, { recursive: true });
|
|
1889
|
+
if ((0, import_fs2.existsSync)(destDir)) {
|
|
1890
|
+
(0, import_fs2.rmSync)(destDir, { recursive: true, force: true });
|
|
1891
|
+
}
|
|
1892
|
+
const args = ["clone", "--depth", "1", "--filter=blob:none"];
|
|
1893
|
+
if (spec.ref && spec.ref !== "HEAD") {
|
|
1894
|
+
args.push("--branch", spec.ref);
|
|
1895
|
+
}
|
|
1896
|
+
args.push(url, destDir);
|
|
1897
|
+
(0, import_child_process.execFileSync)("git", args, { stdio: "pipe" });
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
});
|
|
1901
|
+
|
|
1902
|
+
// src/radiant/core/discovery.ts
|
|
1903
|
+
function discoverWorlds(options) {
|
|
1904
|
+
const worlds = [];
|
|
1905
|
+
const warnings = [];
|
|
1906
|
+
const forceRefresh = process.env.NEUROVERSE_REFRESH === "1";
|
|
1907
|
+
const noFetch = process.env.NEUROVERSE_NO_FETCH === "1";
|
|
1908
|
+
const noOrg = options?.disableOrg || process.env.NEUROVERSE_NO_ORG === "1";
|
|
1909
|
+
const userDir = options?.userWorldsDir ?? (0, import_path3.join)((0, import_os2.homedir)(), ".neuroverse", "worlds");
|
|
1910
|
+
if ((0, import_fs3.existsSync)(userDir)) {
|
|
1911
|
+
worlds.push(...loadWorldsFromDir(userDir, "user"));
|
|
1912
|
+
}
|
|
1913
|
+
if (!noOrg && !options?.explicitWorldsDir) {
|
|
1914
|
+
const specs = [];
|
|
1915
|
+
if (options?.repoDir) {
|
|
1916
|
+
const fromGit = detectOrgExtendsSpec(options.repoDir);
|
|
1917
|
+
if (fromGit) specs.push(fromGit);
|
|
1918
|
+
}
|
|
1919
|
+
if (options?.scopeOwner) {
|
|
1920
|
+
const already = specs.some(
|
|
1921
|
+
(s) => s.owner?.toLowerCase() === options.scopeOwner.toLowerCase()
|
|
1922
|
+
);
|
|
1923
|
+
if (!already) {
|
|
1924
|
+
specs.push({
|
|
1925
|
+
raw: `github:${options.scopeOwner}/worlds`,
|
|
1926
|
+
kind: "github",
|
|
1927
|
+
owner: options.scopeOwner,
|
|
1928
|
+
repo: "worlds"
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
const baseDir = options?.repoDir ?? process.cwd();
|
|
1933
|
+
for (const spec of specs) {
|
|
1934
|
+
const result = resolveExtendsSpec(spec, baseDir, {
|
|
1935
|
+
cacheDir: options?.extendsCacheDir,
|
|
1936
|
+
fetcher: options?.extendsFetcher,
|
|
1937
|
+
ttlMs: options?.extendsTtlMs,
|
|
1938
|
+
forceRefresh,
|
|
1939
|
+
noFetch,
|
|
1940
|
+
silentOnMissing: true
|
|
1941
|
+
});
|
|
1942
|
+
worlds.push(...loadExtendsWorlds(result, "org"));
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
if (options?.repoDir && !options.disableExtends && !options.explicitWorldsDir) {
|
|
1946
|
+
const results = resolveAllExtends(options.repoDir, {
|
|
1947
|
+
cacheDir: options.extendsCacheDir,
|
|
1948
|
+
fetcher: options.extendsFetcher,
|
|
1949
|
+
ttlMs: options.extendsTtlMs,
|
|
1950
|
+
forceRefresh,
|
|
1951
|
+
noFetch
|
|
1952
|
+
});
|
|
1953
|
+
for (const result of results) {
|
|
1954
|
+
worlds.push(...loadExtendsWorlds(result, "extends"));
|
|
1955
|
+
if (result.warning) warnings.push(result.warning);
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
if (options?.explicitWorldsDir) {
|
|
1959
|
+
worlds.push(...loadWorldsFromDir(options.explicitWorldsDir, "repo"));
|
|
1960
|
+
} else if (options?.repoDir) {
|
|
1961
|
+
const repoPaths = [
|
|
1962
|
+
(0, import_path3.join)(options.repoDir, "worlds"),
|
|
1963
|
+
(0, import_path3.join)(options.repoDir, ".neuroverse", "worlds")
|
|
1964
|
+
];
|
|
1965
|
+
for (const p of repoPaths) {
|
|
1966
|
+
if ((0, import_fs3.existsSync)(p)) {
|
|
1967
|
+
worlds.push(...loadWorldsFromDir(p, "repo"));
|
|
1968
|
+
break;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
const combinedContent = worlds.map((w) => {
|
|
1973
|
+
const tag = w.extendsFrom ? `<!-- world: ${w.name} (${w.source} ${w.extendsFrom}) -->` : `<!-- world: ${w.name} (${w.source}) -->`;
|
|
1974
|
+
return `${tag}
|
|
1975
|
+
${w.content}`;
|
|
1976
|
+
}).join("\n\n---\n\n");
|
|
1977
|
+
const summary = worlds.length === 0 ? "no worlds discovered" : worlds.map((w) => `${w.name} (${w.source})`).join(", ");
|
|
1978
|
+
return { worlds, combinedContent, summary, warnings };
|
|
1979
|
+
}
|
|
1980
|
+
function formatActiveWorlds(stack) {
|
|
1981
|
+
if (stack.worlds.length === 0) return "No worlds loaded.";
|
|
1982
|
+
const lines = ["ACTIVE WORLDS", ""];
|
|
1983
|
+
for (const w of stack.worlds) {
|
|
1984
|
+
const sourceLabel = w.source === "base" ? "universal" : w.source === "user" ? "personal" : w.source === "org" ? `org (${w.extendsFrom ?? "auto"})` : w.source === "extends" ? `shared (${w.extendsFrom ?? "extends"})` : "this repo";
|
|
1985
|
+
lines.push(` ${w.name} (${sourceLabel})`);
|
|
1986
|
+
}
|
|
1987
|
+
if (stack.warnings.length > 0) {
|
|
1988
|
+
lines.push("", "WARNINGS");
|
|
1989
|
+
for (const w of stack.warnings) lines.push(` ${w}`);
|
|
1990
|
+
}
|
|
1991
|
+
return lines.join("\n");
|
|
1992
|
+
}
|
|
1993
|
+
function loadExtendsWorlds(result, source) {
|
|
1994
|
+
if (!result.dir) return [];
|
|
1995
|
+
const loaded = loadWorldsFromDir(result.dir, source);
|
|
1996
|
+
return loaded.map((w) => ({ ...w, extendsFrom: result.spec.raw }));
|
|
1997
|
+
}
|
|
1998
|
+
function loadWorldsFromDir(dirPath, source) {
|
|
1999
|
+
const dir = (0, import_path3.resolve)(dirPath);
|
|
2000
|
+
if (!(0, import_fs3.existsSync)(dir)) return [];
|
|
2001
|
+
const stat = (0, import_fs3.statSync)(dir);
|
|
2002
|
+
if (stat.isFile() && dir.endsWith(".md")) {
|
|
2003
|
+
try {
|
|
2004
|
+
return [{
|
|
2005
|
+
name: (0, import_path3.basename)(dir).replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
2006
|
+
source,
|
|
2007
|
+
path: dir,
|
|
2008
|
+
content: (0, import_fs3.readFileSync)(dir, "utf-8")
|
|
2009
|
+
}];
|
|
2010
|
+
} catch {
|
|
2011
|
+
return [];
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
if (!stat.isDirectory()) return [];
|
|
2015
|
+
const files = (0, import_fs3.readdirSync)(dir).filter(
|
|
2016
|
+
(f) => f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md")
|
|
2017
|
+
).sort();
|
|
2018
|
+
return files.map((f) => {
|
|
2019
|
+
const fullPath = (0, import_path3.join)(dir, f);
|
|
2020
|
+
return {
|
|
2021
|
+
name: f.replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
2022
|
+
source,
|
|
2023
|
+
path: fullPath,
|
|
2024
|
+
content: (0, import_fs3.readFileSync)(fullPath, "utf-8")
|
|
2025
|
+
};
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
var import_fs3, import_path3, import_os2;
|
|
2029
|
+
var init_discovery = __esm({
|
|
2030
|
+
"src/radiant/core/discovery.ts"() {
|
|
2031
|
+
"use strict";
|
|
2032
|
+
import_fs3 = require("fs");
|
|
2033
|
+
import_path3 = require("path");
|
|
2034
|
+
import_os2 = require("os");
|
|
2035
|
+
init_extends();
|
|
2036
|
+
}
|
|
2037
|
+
});
|
|
2038
|
+
|
|
893
2039
|
// src/radiant/adapters/exocortex.ts
|
|
894
|
-
function readExocortex(dirPath) {
|
|
895
|
-
const dir = (0,
|
|
2040
|
+
function readExocortex(dirPath, repoName) {
|
|
2041
|
+
const dir = (0, import_path4.resolve)(dirPath);
|
|
896
2042
|
let filesLoaded = 0;
|
|
897
2043
|
function tryRead(...paths) {
|
|
898
2044
|
for (const p of paths) {
|
|
899
|
-
const full = (0,
|
|
900
|
-
if ((0,
|
|
2045
|
+
const full = (0, import_path4.join)(dir, p);
|
|
2046
|
+
if ((0, import_fs4.existsSync)(full)) {
|
|
901
2047
|
try {
|
|
902
|
-
const content = (0,
|
|
2048
|
+
const content = (0, import_fs4.readFileSync)(full, "utf-8").trim();
|
|
903
2049
|
if (content) {
|
|
904
2050
|
filesLoaded++;
|
|
905
2051
|
return content;
|
|
@@ -910,55 +2056,65 @@ function readExocortex(dirPath) {
|
|
|
910
2056
|
}
|
|
911
2057
|
return null;
|
|
912
2058
|
}
|
|
2059
|
+
const attention = tryRead("attention.md");
|
|
2060
|
+
const goals = tryRead("goals.md");
|
|
2061
|
+
const identity = tryRead("identity.md", "user.md");
|
|
2062
|
+
const organization = tryRead("org/organization.md", "org/src/organization.md");
|
|
2063
|
+
const methods = tryRead("org/methods.md", "org/src/methods.md");
|
|
2064
|
+
let sprint = null;
|
|
2065
|
+
let projectContext = null;
|
|
2066
|
+
if (repoName) {
|
|
2067
|
+
const projectPaths = [
|
|
2068
|
+
repoName,
|
|
2069
|
+
repoName.toLowerCase(),
|
|
2070
|
+
repoName.replace(/-/g, "_")
|
|
2071
|
+
];
|
|
2072
|
+
for (const projectDir of projectPaths) {
|
|
2073
|
+
const projectSprint = tryRead(
|
|
2074
|
+
`${projectDir}/src/sprint.md`,
|
|
2075
|
+
`${projectDir}/sprint.md`
|
|
2076
|
+
);
|
|
2077
|
+
if (projectSprint) {
|
|
2078
|
+
sprint = projectSprint;
|
|
2079
|
+
break;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
for (const projectDir of projectPaths) {
|
|
2083
|
+
const roadmap = tryRead(
|
|
2084
|
+
`${projectDir}/roadmap.md`,
|
|
2085
|
+
`${projectDir}/src/roadmap.md`
|
|
2086
|
+
);
|
|
2087
|
+
if (roadmap) {
|
|
2088
|
+
projectContext = roadmap;
|
|
2089
|
+
break;
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
if (!sprint) {
|
|
2094
|
+
sprint = tryRead("sprint.md", "src/sprint.md");
|
|
2095
|
+
}
|
|
913
2096
|
const ctx = {
|
|
914
|
-
attention
|
|
915
|
-
goals
|
|
916
|
-
identity
|
|
917
|
-
sprint
|
|
918
|
-
organization
|
|
919
|
-
methods
|
|
2097
|
+
attention,
|
|
2098
|
+
goals,
|
|
2099
|
+
identity,
|
|
2100
|
+
sprint,
|
|
2101
|
+
organization,
|
|
2102
|
+
methods,
|
|
920
2103
|
source: dir,
|
|
921
2104
|
filesLoaded
|
|
922
2105
|
};
|
|
923
|
-
|
|
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
|
|
2106
|
+
if (projectContext && ctx.sprint) {
|
|
2107
|
+
ctx.sprint = `${ctx.sprint}
|
|
933
2108
|
|
|
934
|
-
|
|
2109
|
+
---
|
|
2110
|
+
Project roadmap:
|
|
2111
|
+
${projectContext}`;
|
|
2112
|
+
} else if (projectContext) {
|
|
2113
|
+
ctx.sprint = `Project roadmap:
|
|
2114
|
+
${projectContext}`;
|
|
2115
|
+
ctx.filesLoaded++;
|
|
935
2116
|
}
|
|
936
|
-
|
|
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");
|
|
2117
|
+
return ctx;
|
|
962
2118
|
}
|
|
963
2119
|
function summarizeExocortex(ctx) {
|
|
964
2120
|
if (ctx.filesLoaded === 0) return "no exocortex files found";
|
|
@@ -971,33 +2127,33 @@ function summarizeExocortex(ctx) {
|
|
|
971
2127
|
if (ctx.methods) loaded.push("methods");
|
|
972
2128
|
return `${loaded.join(", ")} (${ctx.filesLoaded} files)`;
|
|
973
2129
|
}
|
|
974
|
-
var
|
|
2130
|
+
var import_fs4, import_path4;
|
|
975
2131
|
var init_exocortex = __esm({
|
|
976
2132
|
"src/radiant/adapters/exocortex.ts"() {
|
|
977
2133
|
"use strict";
|
|
978
|
-
|
|
979
|
-
|
|
2134
|
+
import_fs4 = require("fs");
|
|
2135
|
+
import_path4 = require("path");
|
|
980
2136
|
}
|
|
981
2137
|
});
|
|
982
2138
|
|
|
983
2139
|
// src/radiant/memory/palace.ts
|
|
984
2140
|
function writeRead(exocortexDir, frontmatter, text) {
|
|
985
|
-
const dir = (0,
|
|
986
|
-
(0,
|
|
2141
|
+
const dir = (0, import_path5.resolve)(exocortexDir, "radiant", "reads");
|
|
2142
|
+
(0, import_fs5.mkdirSync)(dir, { recursive: true });
|
|
987
2143
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
988
2144
|
const filename = `${date}.md`;
|
|
989
|
-
const filepath = (0,
|
|
2145
|
+
const filepath = (0, import_path5.join)(dir, filename);
|
|
990
2146
|
const content = `${frontmatter}
|
|
991
2147
|
|
|
992
2148
|
${text}
|
|
993
2149
|
`;
|
|
994
|
-
(0,
|
|
2150
|
+
(0, import_fs5.writeFileSync)(filepath, content, "utf-8");
|
|
995
2151
|
return filepath;
|
|
996
2152
|
}
|
|
997
2153
|
function updateKnowledge(exocortexDir, persistence, options) {
|
|
998
|
-
const dir = (0,
|
|
999
|
-
(0,
|
|
1000
|
-
const filepath = (0,
|
|
2154
|
+
const dir = (0, import_path5.resolve)(exocortexDir, "radiant");
|
|
2155
|
+
(0, import_fs5.mkdirSync)(dir, { recursive: true });
|
|
2156
|
+
const filepath = (0, import_path5.join)(dir, "knowledge.md");
|
|
1001
2157
|
const totalReads = options?.totalReads ?? 0;
|
|
1002
2158
|
const existingUntriggered = loadUntriggeredCounts(filepath);
|
|
1003
2159
|
const lines = [
|
|
@@ -1084,14 +2240,14 @@ function updateKnowledge(exocortexDir, persistence, options) {
|
|
|
1084
2240
|
lines.push(`${name}=${count}`);
|
|
1085
2241
|
}
|
|
1086
2242
|
lines.push("-->");
|
|
1087
|
-
(0,
|
|
2243
|
+
(0, import_fs5.writeFileSync)(filepath, lines.join("\n"), "utf-8");
|
|
1088
2244
|
return filepath;
|
|
1089
2245
|
}
|
|
1090
2246
|
function loadUntriggeredCounts(filepath) {
|
|
1091
2247
|
const counts = /* @__PURE__ */ new Map();
|
|
1092
|
-
if (!(0,
|
|
2248
|
+
if (!(0, import_fs5.existsSync)(filepath)) return counts;
|
|
1093
2249
|
try {
|
|
1094
|
-
const content = (0,
|
|
2250
|
+
const content = (0, import_fs5.readFileSync)(filepath, "utf-8");
|
|
1095
2251
|
const match = content.match(
|
|
1096
2252
|
/<!-- untriggered_counts[\s\S]*?-->/
|
|
1097
2253
|
);
|
|
@@ -1109,13 +2265,13 @@ function loadUntriggeredCounts(filepath) {
|
|
|
1109
2265
|
return counts;
|
|
1110
2266
|
}
|
|
1111
2267
|
function loadPriorReads(exocortexDir) {
|
|
1112
|
-
const dir = (0,
|
|
1113
|
-
if (!(0,
|
|
1114
|
-
const files = (0,
|
|
2268
|
+
const dir = (0, import_path5.resolve)(exocortexDir, "radiant", "reads");
|
|
2269
|
+
if (!(0, import_fs5.existsSync)(dir)) return [];
|
|
2270
|
+
const files = (0, import_fs5.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
1115
2271
|
const reads = [];
|
|
1116
2272
|
for (const filename of files) {
|
|
1117
|
-
const filepath = (0,
|
|
1118
|
-
const content = (0,
|
|
2273
|
+
const filepath = (0, import_path5.join)(dir, filename);
|
|
2274
|
+
const content = (0, import_fs5.readFileSync)(filepath, "utf-8");
|
|
1119
2275
|
const date = filename.replace(".md", "");
|
|
1120
2276
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1121
2277
|
const frontmatter = fmMatch ? fmMatch[1] : "";
|
|
@@ -1149,33 +2305,12 @@ function computePersistence(priorReads, currentPatternNames) {
|
|
|
1149
2305
|
dates: dates.sort()
|
|
1150
2306
|
})).sort((a, b) => b.occurrences - a.occurrences);
|
|
1151
2307
|
}
|
|
1152
|
-
|
|
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;
|
|
2308
|
+
var import_fs5, import_path5;
|
|
1174
2309
|
var init_palace = __esm({
|
|
1175
2310
|
"src/radiant/memory/palace.ts"() {
|
|
1176
2311
|
"use strict";
|
|
1177
|
-
|
|
1178
|
-
|
|
2312
|
+
import_fs5 = require("fs");
|
|
2313
|
+
import_path5 = require("path");
|
|
1179
2314
|
}
|
|
1180
2315
|
});
|
|
1181
2316
|
|
|
@@ -2284,10 +3419,10 @@ var init_guard_engine = __esm({
|
|
|
2284
3419
|
// src/loader/world-loader.ts
|
|
2285
3420
|
async function loadWorldFromDirectory(dirPath) {
|
|
2286
3421
|
const { readFile } = await import("fs/promises");
|
|
2287
|
-
const { join:
|
|
2288
|
-
const { readdirSync:
|
|
3422
|
+
const { join: join8 } = await import("path");
|
|
3423
|
+
const { readdirSync: readdirSync6 } = await import("fs");
|
|
2289
3424
|
async function readJson(filename) {
|
|
2290
|
-
const filePath =
|
|
3425
|
+
const filePath = join8(dirPath, filename);
|
|
2291
3426
|
try {
|
|
2292
3427
|
const content = await readFile(filePath, "utf-8");
|
|
2293
3428
|
return JSON.parse(content);
|
|
@@ -2317,11 +3452,11 @@ async function loadWorldFromDirectory(dirPath) {
|
|
|
2317
3452
|
const metadataJson = await readJson("metadata.json");
|
|
2318
3453
|
const rules = [];
|
|
2319
3454
|
try {
|
|
2320
|
-
const rulesDir =
|
|
2321
|
-
const ruleFiles =
|
|
3455
|
+
const rulesDir = join8(dirPath, "rules");
|
|
3456
|
+
const ruleFiles = readdirSync6(rulesDir).filter((f) => f.endsWith(".json")).sort();
|
|
2322
3457
|
for (const file of ruleFiles) {
|
|
2323
3458
|
try {
|
|
2324
|
-
const content = await readFile(
|
|
3459
|
+
const content = await readFile(join8(rulesDir, file), "utf-8");
|
|
2325
3460
|
rules.push(JSON.parse(content));
|
|
2326
3461
|
} catch (err) {
|
|
2327
3462
|
process.stderr.write(
|
|
@@ -2728,15 +3863,17 @@ function buildInterpretationPrompt(input) {
|
|
|
2728
3863
|
const eventSample = formatEventSample(input.events, 30);
|
|
2729
3864
|
const canonicalList = (input.canonicalPatterns ?? []).length > 0 ? `Patterns the organization has already named (use these names if you see them):
|
|
2730
3865
|
${input.canonicalPatterns.map((p) => `- ${p}`).join("\n")}` : "No patterns have been named yet. Everything you observe is new.";
|
|
3866
|
+
const compressedWorld = compressWorldmodel(input.worldmodelContent);
|
|
3867
|
+
const cl = compressLens(input.lens);
|
|
2731
3868
|
const frame = input.lens.primary_frame;
|
|
2732
3869
|
const evalQuestions = frame.evaluation_questions.map((q, i) => `${i + 1}. ${q}`).join("\n");
|
|
2733
|
-
const forbiddenList =
|
|
2734
|
-
const jargonTable =
|
|
3870
|
+
const forbiddenList = cl.forbiddenPhrases;
|
|
3871
|
+
const jargonTable = cl.jargonTranslations;
|
|
2735
3872
|
return `You are a behavioral intelligence system reading team activity and producing a read for the reader who needs to act on it.
|
|
2736
3873
|
|
|
2737
|
-
##
|
|
3874
|
+
## Worldmodel (compressed)
|
|
2738
3875
|
|
|
2739
|
-
${
|
|
3876
|
+
${compressedWorld}
|
|
2740
3877
|
|
|
2741
3878
|
## What happened this window
|
|
2742
3879
|
|
|
@@ -2915,6 +4052,7 @@ function isPatternLike(x) {
|
|
|
2915
4052
|
var init_patterns = __esm({
|
|
2916
4053
|
"src/radiant/core/patterns.ts"() {
|
|
2917
4054
|
"use strict";
|
|
4055
|
+
init_compress();
|
|
2918
4056
|
}
|
|
2919
4057
|
});
|
|
2920
4058
|
|
|
@@ -2932,30 +4070,16 @@ Window: last ${input.windowDays} days \xB7 ${input.eventCount} events
|
|
|
2932
4070
|
Lens: ${input.lens.name}`
|
|
2933
4071
|
);
|
|
2934
4072
|
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
4073
|
let emergentBlock = "EMERGENT\n";
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
emergentBlock += `
|
|
4074
|
+
for (const p of input.patterns) {
|
|
4075
|
+
emergentBlock += `
|
|
2941
4076
|
${p.name}
|
|
2942
4077
|
`;
|
|
2943
|
-
|
|
4078
|
+
emergentBlock += ` ${p.description}
|
|
2944
4079
|
`;
|
|
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}
|
|
2954
|
-
`;
|
|
2955
|
-
if (p.evidence.cited_invariant) {
|
|
2956
|
-
emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
|
|
4080
|
+
if (p.evidence.cited_invariant) {
|
|
4081
|
+
emergentBlock += ` Cited invariant: ${p.evidence.cited_invariant}
|
|
2957
4082
|
`;
|
|
2958
|
-
}
|
|
2959
4083
|
}
|
|
2960
4084
|
}
|
|
2961
4085
|
sections.push(emergentBlock.trimEnd());
|
|
@@ -3174,16 +4298,29 @@ var init_renderer = __esm({
|
|
|
3174
4298
|
async function emergent(input) {
|
|
3175
4299
|
const lens = resolveLens2(input.lensId);
|
|
3176
4300
|
const windowDays = input.windowDays ?? 14;
|
|
4301
|
+
let worldStack;
|
|
4302
|
+
let worldmodelContent = input.worldmodelContent;
|
|
4303
|
+
if (!worldmodelContent || worldmodelContent.trim() === "") {
|
|
4304
|
+
worldStack = discoverWorlds({ explicitWorldsDir: input.worldPath });
|
|
4305
|
+
worldmodelContent = worldStack.combinedContent;
|
|
4306
|
+
}
|
|
3177
4307
|
let statedIntent;
|
|
3178
4308
|
let exocortexContext;
|
|
3179
4309
|
let priorReadContext = "";
|
|
3180
4310
|
if (input.exocortexPath) {
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
4311
|
+
const repoName = input.scope.type === "repo" ? input.scope.repo : void 0;
|
|
4312
|
+
exocortexContext = readExocortex(input.exocortexPath, repoName);
|
|
4313
|
+
const compressed = compressExocortex(exocortexContext);
|
|
4314
|
+
if (compressed) {
|
|
4315
|
+
statedIntent = `## Stated Intent (from exocortex, compressed)
|
|
4316
|
+
|
|
4317
|
+
${compressed}
|
|
4318
|
+
|
|
4319
|
+
Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
4320
|
+
}
|
|
3184
4321
|
const priorReads = loadPriorReads(input.exocortexPath);
|
|
3185
4322
|
if (priorReads.length > 0) {
|
|
3186
|
-
priorReadContext =
|
|
4323
|
+
priorReadContext = compressPriorReads(priorReads);
|
|
3187
4324
|
}
|
|
3188
4325
|
}
|
|
3189
4326
|
let events;
|
|
@@ -3201,6 +4338,40 @@ async function emergent(input) {
|
|
|
3201
4338
|
windowDays
|
|
3202
4339
|
});
|
|
3203
4340
|
}
|
|
4341
|
+
let adapterSignals = "";
|
|
4342
|
+
const activeAdapters = ["github"];
|
|
4343
|
+
const discordToken = process.env.DISCORD_TOKEN;
|
|
4344
|
+
const discordGuild = process.env.DISCORD_GUILD_ID;
|
|
4345
|
+
if (discordToken && discordGuild) {
|
|
4346
|
+
try {
|
|
4347
|
+
const discord = await fetchDiscordActivity(discordGuild, discordToken, { windowDays });
|
|
4348
|
+
events.push(...discord.events);
|
|
4349
|
+
adapterSignals += "\n\n" + formatDiscordSignalsForPrompt(discord.signals);
|
|
4350
|
+
activeAdapters.push("discord");
|
|
4351
|
+
} catch {
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
const slackToken = process.env.SLACK_TOKEN;
|
|
4355
|
+
if (slackToken) {
|
|
4356
|
+
try {
|
|
4357
|
+
const slack = await fetchSlackActivity(slackToken, { windowDays });
|
|
4358
|
+
events.push(...slack.events);
|
|
4359
|
+
adapterSignals += "\n\n" + formatSlackSignalsForPrompt(slack.signals);
|
|
4360
|
+
activeAdapters.push("slack");
|
|
4361
|
+
} catch {
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
const notionToken = process.env.NOTION_TOKEN;
|
|
4365
|
+
if (notionToken) {
|
|
4366
|
+
try {
|
|
4367
|
+
const notion = await fetchNotionActivity(notionToken, { windowDays });
|
|
4368
|
+
events.push(...notion.events);
|
|
4369
|
+
adapterSignals += "\n\n" + formatNotionSignalsForPrompt(notion.signals);
|
|
4370
|
+
activeAdapters.push("notion");
|
|
4371
|
+
} catch {
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
3204
4375
|
const classified = classifyEvents(events);
|
|
3205
4376
|
const signals = extractSignals(classified);
|
|
3206
4377
|
const scores = computeScores(signals, input.worldmodelContent !== "");
|
|
@@ -3211,7 +4382,7 @@ async function emergent(input) {
|
|
|
3211
4382
|
lens,
|
|
3212
4383
|
ai: input.ai,
|
|
3213
4384
|
canonicalPatterns: input.canonicalPatterns,
|
|
3214
|
-
statedIntent: statedIntent
|
|
4385
|
+
statedIntent: [statedIntent, adapterSignals, priorReadContext].filter(Boolean).join("\n\n") || void 0
|
|
3215
4386
|
});
|
|
3216
4387
|
const rewrittenPatterns = patterns.map((p) => lens.rewrite(p));
|
|
3217
4388
|
const allDescriptions = rewrittenPatterns.map((p) => p.description).join("\n");
|
|
@@ -3260,7 +4431,9 @@ async function emergent(input) {
|
|
|
3260
4431
|
voiceClean: voiceViolations.length === 0,
|
|
3261
4432
|
signals,
|
|
3262
4433
|
scores,
|
|
3263
|
-
eventCount: events.length
|
|
4434
|
+
eventCount: events.length,
|
|
4435
|
+
activeAdapters,
|
|
4436
|
+
worldStack
|
|
3264
4437
|
};
|
|
3265
4438
|
}
|
|
3266
4439
|
function computeScores(signals, worldmodelLoaded) {
|
|
@@ -3315,8 +4488,13 @@ var init_emergent = __esm({
|
|
|
3315
4488
|
"use strict";
|
|
3316
4489
|
init_lenses();
|
|
3317
4490
|
init_github();
|
|
4491
|
+
init_discord();
|
|
4492
|
+
init_slack();
|
|
4493
|
+
init_notion();
|
|
4494
|
+
init_discovery();
|
|
3318
4495
|
init_exocortex();
|
|
3319
4496
|
init_palace();
|
|
4497
|
+
init_compress();
|
|
3320
4498
|
init_governance();
|
|
3321
4499
|
init_signals();
|
|
3322
4500
|
init_math();
|
|
@@ -3373,22 +4551,22 @@ __export(server_exports, {
|
|
|
3373
4551
|
startRadiantMcp: () => startRadiantMcp
|
|
3374
4552
|
});
|
|
3375
4553
|
function loadWorldmodelContent(worldsPath) {
|
|
3376
|
-
const resolved = (0,
|
|
3377
|
-
if (!(0,
|
|
4554
|
+
const resolved = (0, import_path6.resolve)(worldsPath);
|
|
4555
|
+
if (!(0, import_fs6.existsSync)(resolved)) {
|
|
3378
4556
|
throw new Error(`Worlds path not found: ${resolved}`);
|
|
3379
4557
|
}
|
|
3380
|
-
const stat = (0,
|
|
4558
|
+
const stat = (0, import_fs6.statSync)(resolved);
|
|
3381
4559
|
if (stat.isFile()) {
|
|
3382
|
-
return (0,
|
|
4560
|
+
return (0, import_fs6.readFileSync)(resolved, "utf-8");
|
|
3383
4561
|
}
|
|
3384
4562
|
if (stat.isDirectory()) {
|
|
3385
|
-
const files = (0,
|
|
3386
|
-
(f) => (0,
|
|
4563
|
+
const files = (0, import_fs6.readdirSync)(resolved).filter(
|
|
4564
|
+
(f) => (0, import_path6.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
|
|
3387
4565
|
).sort();
|
|
3388
4566
|
if (files.length === 0) {
|
|
3389
4567
|
throw new Error(`No worldmodel files found in ${resolved}`);
|
|
3390
4568
|
}
|
|
3391
|
-
return files.map((f) => (0,
|
|
4569
|
+
return files.map((f) => (0, import_fs6.readFileSync)((0, import_path6.join)(resolved, f), "utf-8")).join("\n\n---\n\n");
|
|
3392
4570
|
}
|
|
3393
4571
|
throw new Error(`Worlds path is neither a file nor directory: ${resolved}`);
|
|
3394
4572
|
}
|
|
@@ -3407,12 +4585,12 @@ async function startRadiantMcp(args) {
|
|
|
3407
4585
|
const server = new RadiantMcpServer({ worldsPath, lensId, model });
|
|
3408
4586
|
await server.start();
|
|
3409
4587
|
}
|
|
3410
|
-
var
|
|
4588
|
+
var import_fs6, import_path6, TOOLS, RadiantMcpServer;
|
|
3411
4589
|
var init_server = __esm({
|
|
3412
4590
|
"src/radiant/mcp/server.ts"() {
|
|
3413
4591
|
"use strict";
|
|
3414
|
-
|
|
3415
|
-
|
|
4592
|
+
import_fs6 = require("fs");
|
|
4593
|
+
import_path6 = require("path");
|
|
3416
4594
|
init_think();
|
|
3417
4595
|
init_emergent();
|
|
3418
4596
|
init_ai();
|
|
@@ -3643,14 +4821,15 @@ __export(radiant_exports, {
|
|
|
3643
4821
|
main: () => main
|
|
3644
4822
|
});
|
|
3645
4823
|
module.exports = __toCommonJS(radiant_exports);
|
|
3646
|
-
var
|
|
3647
|
-
var
|
|
4824
|
+
var import_fs7 = require("fs");
|
|
4825
|
+
var import_path7 = require("path");
|
|
3648
4826
|
init_think();
|
|
3649
4827
|
init_emergent();
|
|
3650
4828
|
init_ai();
|
|
3651
4829
|
init_scopes();
|
|
3652
4830
|
init_exocortex();
|
|
3653
4831
|
init_lenses();
|
|
4832
|
+
init_discovery();
|
|
3654
4833
|
var RED = "\x1B[31m";
|
|
3655
4834
|
var DIM = "\x1B[2m";
|
|
3656
4835
|
var BOLD = "\x1B[1m";
|
|
@@ -3676,6 +4855,18 @@ ${BOLD}Usage:${RESET}
|
|
|
3676
4855
|
neuroverse radiant lenses list
|
|
3677
4856
|
neuroverse radiant lenses describe auki-builder
|
|
3678
4857
|
|
|
4858
|
+
${BOLD}Auto-discovery:${RESET}
|
|
4859
|
+
You do not need to clone the target repo.
|
|
4860
|
+
|
|
4861
|
+
radiant emergent NeuroverseOS/ \u2192 probes github.com/NeuroverseOS/worlds
|
|
4862
|
+
radiant emergent aukiverse/posemesh \u2192 probes github.com/aukiverse/worlds
|
|
4863
|
+
|
|
4864
|
+
The scope argument itself is enough. Discovery also picks up
|
|
4865
|
+
~/.neuroverse/worlds/ (personal), the org from your current clone's
|
|
4866
|
+
.git/config (if any), and ./worlds/ (this repo).
|
|
4867
|
+
|
|
4868
|
+
Set NEUROVERSE_NO_ORG=1 to disable org probing for a single run.
|
|
4869
|
+
|
|
3679
4870
|
${BOLD}Environment:${RESET}
|
|
3680
4871
|
ANTHROPIC_API_KEY Required for AI commands (think, emergent, decision)
|
|
3681
4872
|
RADIANT_WORLDS Default worlds directory (overridden by --worlds)
|
|
@@ -3742,17 +4933,17 @@ function parseArgs(argv) {
|
|
|
3742
4933
|
return result;
|
|
3743
4934
|
}
|
|
3744
4935
|
function loadWorldmodelContent2(worldsPath) {
|
|
3745
|
-
const resolved = (0,
|
|
3746
|
-
if (!(0,
|
|
4936
|
+
const resolved = (0, import_path7.resolve)(worldsPath);
|
|
4937
|
+
if (!(0, import_fs7.existsSync)(resolved)) {
|
|
3747
4938
|
throw new Error(`Worlds path not found: ${resolved}`);
|
|
3748
4939
|
}
|
|
3749
|
-
const stat = (0,
|
|
4940
|
+
const stat = (0, import_fs7.statSync)(resolved);
|
|
3750
4941
|
if (stat.isFile()) {
|
|
3751
|
-
return (0,
|
|
4942
|
+
return (0, import_fs7.readFileSync)(resolved, "utf-8");
|
|
3752
4943
|
}
|
|
3753
4944
|
if (stat.isDirectory()) {
|
|
3754
|
-
const files = (0,
|
|
3755
|
-
(f) => (0,
|
|
4945
|
+
const files = (0, import_fs7.readdirSync)(resolved).filter(
|
|
4946
|
+
(f) => (0, import_path7.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
|
|
3756
4947
|
).sort();
|
|
3757
4948
|
if (files.length === 0) {
|
|
3758
4949
|
throw new Error(
|
|
@@ -3760,27 +4951,55 @@ function loadWorldmodelContent2(worldsPath) {
|
|
|
3760
4951
|
);
|
|
3761
4952
|
}
|
|
3762
4953
|
return files.map((f) => {
|
|
3763
|
-
const content = (0,
|
|
4954
|
+
const content = (0, import_fs7.readFileSync)((0, import_path7.join)(resolved, f), "utf-8");
|
|
3764
4955
|
return `<!-- worldmodel: ${f} -->
|
|
3765
4956
|
${content}`;
|
|
3766
4957
|
}).join("\n\n---\n\n");
|
|
3767
4958
|
}
|
|
3768
4959
|
throw new Error(`Worlds path is neither a file nor a directory: ${resolved}`);
|
|
3769
4960
|
}
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
4961
|
+
function resolveWorldmodelContent(explicitPath, scopeOwner) {
|
|
4962
|
+
if (explicitPath) {
|
|
4963
|
+
return loadWorldmodelContent2(explicitPath);
|
|
4964
|
+
}
|
|
4965
|
+
const stack = discoverWorlds({
|
|
4966
|
+
repoDir: process.cwd(),
|
|
4967
|
+
scopeOwner
|
|
4968
|
+
});
|
|
4969
|
+
if (stack.worlds.length === 0) {
|
|
4970
|
+
const scopeLine = scopeOwner ? ` 3. github:${scopeOwner}/worlds (from scope arg)
|
|
4971
|
+
` : "";
|
|
4972
|
+
const ext = scopeOwner ? 4 : 3;
|
|
4973
|
+
const repo = scopeOwner ? 5 : 4;
|
|
3773
4974
|
process.stderr.write(
|
|
3774
|
-
`${RED}Error:${RESET}
|
|
3775
|
-
${DIM}
|
|
4975
|
+
`${RED}Error:${RESET} No worldmodel found.
|
|
4976
|
+
${DIM}Tried (in order):
|
|
4977
|
+
1. ~/.neuroverse/worlds/ (user tier)
|
|
4978
|
+
2. github:<owner>/worlds (org auto-detect from git remote)
|
|
4979
|
+
` + scopeLine + ` ${ext}. .neuroverse/config.json extends (explicit shared worlds)
|
|
4980
|
+
${repo}. ./worlds/ or ./.neuroverse/worlds/ (repo tier)
|
|
4981
|
+
|
|
4982
|
+
Pass --worlds <dir> or set RADIANT_WORLDS to specify explicitly.
|
|
4983
|
+
Or run against a <scope>/ where github.com/<scope>/worlds exists.${RESET}
|
|
3776
4984
|
`
|
|
3777
4985
|
);
|
|
3778
4986
|
process.exit(1);
|
|
3779
4987
|
}
|
|
3780
|
-
|
|
3781
|
-
|
|
4988
|
+
process.stderr.write(`${DIM}${formatActiveWorlds(stack)}${RESET}
|
|
4989
|
+
|
|
4990
|
+
`);
|
|
4991
|
+
for (const warning of stack.warnings) {
|
|
4992
|
+
process.stderr.write(`${YELLOW}\u26A0${RESET} ${warning}
|
|
4993
|
+
`);
|
|
4994
|
+
}
|
|
4995
|
+
return stack.combinedContent;
|
|
4996
|
+
}
|
|
4997
|
+
async function cmdThink(args) {
|
|
4998
|
+
const lensId = args.lens ?? process.env.RADIANT_LENS;
|
|
4999
|
+
if (!lensId) {
|
|
3782
5000
|
process.stderr.write(
|
|
3783
|
-
`${RED}Error:${RESET} --
|
|
5001
|
+
`${RED}Error:${RESET} --lens <id> or RADIANT_LENS required.
|
|
5002
|
+
${DIM}Available lenses: ${listLenses().join(", ")}${RESET}
|
|
3784
5003
|
`
|
|
3785
5004
|
);
|
|
3786
5005
|
process.exit(1);
|
|
@@ -3799,7 +5018,7 @@ ${DIM}Set it to your Anthropic API key to use Radiant's AI features.${RESET}
|
|
|
3799
5018
|
query = args.rest.join(" ");
|
|
3800
5019
|
}
|
|
3801
5020
|
if (!query && !process.stdin.isTTY) {
|
|
3802
|
-
query = (0,
|
|
5021
|
+
query = (0, import_fs7.readFileSync)(0, "utf-8").trim();
|
|
3803
5022
|
}
|
|
3804
5023
|
if (!query) {
|
|
3805
5024
|
process.stderr.write(
|
|
@@ -3809,12 +5028,12 @@ ${DIM}Use --query "...", pass as trailing args, or pipe via stdin.${RESET}
|
|
|
3809
5028
|
);
|
|
3810
5029
|
process.exit(1);
|
|
3811
5030
|
}
|
|
3812
|
-
const
|
|
5031
|
+
const explicitWorldsPath = args.worlds ?? process.env.RADIANT_WORLDS;
|
|
5032
|
+
const worldmodelContent = resolveWorldmodelContent(explicitWorldsPath);
|
|
3813
5033
|
const model = args.model ?? process.env.RADIANT_MODEL;
|
|
3814
5034
|
const ai = createAnthropicAI(apiKey, model || void 0);
|
|
3815
5035
|
process.stderr.write(
|
|
3816
|
-
`${DIM}
|
|
3817
|
-
${DIM}Lens: ${lensId}${RESET}
|
|
5036
|
+
`${DIM}Lens: ${lensId}${RESET}
|
|
3818
5037
|
${DIM}Model: ${model ?? "claude-sonnet-4-20250514 (default)"}${RESET}
|
|
3819
5038
|
|
|
3820
5039
|
`
|
|
@@ -3873,14 +5092,6 @@ async function cmdEmergent(args) {
|
|
|
3873
5092
|
process.stderr.write(
|
|
3874
5093
|
`${RED}Error:${RESET} --lens <id> or RADIANT_LENS required.
|
|
3875
5094
|
${DIM}Available lenses: ${listLenses().join(", ")}${RESET}
|
|
3876
|
-
`
|
|
3877
|
-
);
|
|
3878
|
-
process.exit(1);
|
|
3879
|
-
}
|
|
3880
|
-
const worldsPath = args.worlds ?? process.env.RADIANT_WORLDS;
|
|
3881
|
-
if (!worldsPath) {
|
|
3882
|
-
process.stderr.write(
|
|
3883
|
-
`${RED}Error:${RESET} --worlds <dir> or RADIANT_WORLDS required.
|
|
3884
5095
|
`
|
|
3885
5096
|
);
|
|
3886
5097
|
process.exit(1);
|
|
@@ -3902,7 +5113,11 @@ ${DIM}Set it to a GitHub PAT with repo read access.${RESET}
|
|
|
3902
5113
|
);
|
|
3903
5114
|
process.exit(1);
|
|
3904
5115
|
}
|
|
3905
|
-
const
|
|
5116
|
+
const explicitWorldsPath = args.worlds ?? process.env.RADIANT_WORLDS;
|
|
5117
|
+
const worldmodelContent = resolveWorldmodelContent(
|
|
5118
|
+
explicitWorldsPath,
|
|
5119
|
+
scope.owner
|
|
5120
|
+
);
|
|
3906
5121
|
const model = args.model ?? process.env.RADIANT_MODEL;
|
|
3907
5122
|
const ai = createAnthropicAI(anthropicKey, model || void 0);
|
|
3908
5123
|
const view = args.view ?? process.env.RADIANT_VIEW ?? "community";
|