@neuroverseos/governance 0.8.1 → 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 +119 -1
- package/dist/{chunk-ETDIEVAX.js → chunk-3ZWU7C43.js} +331 -45
- package/dist/{chunk-F2LWMOM5.js → chunk-TCGGED4G.js} +14 -14
- package/dist/cli/neuroverse.cjs +591 -205
- package/dist/cli/radiant.cjs +440 -103
- package/dist/cli/radiant.js +62 -24
- package/dist/cli/worldmodel.cjs +1055 -1000
- package/dist/cli/worldmodel.js +40 -0
- package/dist/{lenses-YDMKSXDL.js → lenses-XDWK6ZKI.js} +1 -1
- package/dist/radiant/index.cjs +352 -53
- package/dist/radiant/index.d.cts +145 -10
- package/dist/radiant/index.d.ts +145 -10
- package/dist/radiant/index.js +20 -2
- package/dist/{server-ZSQ6DRSN.js → server-JKUBUK5H.js} +2 -2
- package/examples/radiant-weekly-workflow.yml +81 -0
- package/package.json +2 -1
package/AGENTS.md
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
Runtime containment for AI agents. Define what an agent can and cannot do, then enforce it at every action. Deterministic — same event + same rules = same verdict. No LLM in the evaluation loop.
|
|
6
6
|
|
|
7
|
+
> **Where the NeuroverseOS worldmodel lives.** The canonical Sovereign Conduit
|
|
8
|
+
> worldmodel is at [github.com/NeuroverseOS/Worlds](https://github.com/NeuroverseOS/Worlds).
|
|
9
|
+
> Every NeuroverseOS repo — including this one — auto-loads it via the
|
|
10
|
+
> org-detect discovery tier. A reference sample sits at
|
|
11
|
+
> `src/radiant/examples/neuroverse-base/` (alongside `src/radiant/examples/auki/`)
|
|
12
|
+
> for developers who want to see the format. Do not edit the sample — edit the
|
|
13
|
+
> source.
|
|
14
|
+
|
|
7
15
|
## Quick Start for Agents
|
|
8
16
|
|
|
9
17
|
### Install
|
package/README.md
CHANGED
|
@@ -548,7 +548,7 @@ A World is a `.nv-world.md` file. It contains everything:
|
|
|
548
548
|
| **Guards** | Domain-specific enforcement |
|
|
549
549
|
| **Gates** | Viability classification |
|
|
550
550
|
|
|
551
|
-
|
|
551
|
+
Four ways to create a world. All produce the same `WorldDefinition` object:
|
|
552
552
|
|
|
553
553
|
```
|
|
554
554
|
Path 1: Configurator (12 questions)
|
|
@@ -559,6 +559,9 @@ Path 2: CLI
|
|
|
559
559
|
|
|
560
560
|
Path 3: Code
|
|
561
561
|
defineWorld({...}) → WorldDefinition
|
|
562
|
+
|
|
563
|
+
Path 4: World Model Builder (mission + skills + values + overlaps)
|
|
564
|
+
.worldmodel.md → neuroverse worldmodel build → .nv-world.md → WorldDefinition
|
|
562
565
|
```
|
|
563
566
|
|
|
564
567
|
All three work with the same runtime. A world created through the configurator works identically to one written by hand.
|
|
@@ -747,6 +750,7 @@ const verdict = evaluatePlan({ intent: 'buy billboard ads' }, plan);
|
|
|
747
750
|
| `neuroverse mcp` | MCP governance server |
|
|
748
751
|
| `neuroverse plan` | Plan enforcement commands |
|
|
749
752
|
| `neuroverse lens` | Manage behavioral lenses (list, preview, compile) |
|
|
753
|
+
| `neuroverse worldmodel` | Behavioral world model builder (init, validate, build, explain) |
|
|
750
754
|
|
|
751
755
|
### Lens CLI
|
|
752
756
|
|
|
@@ -770,6 +774,120 @@ neuroverse lens compare --input "I'm stressed" --lenses stoic,coach,calm
|
|
|
770
774
|
neuroverse lens add --world ./world/ --name "Support" --tagline "Patient and clear" --emotion warm
|
|
771
775
|
```
|
|
772
776
|
|
|
777
|
+
### World Model CLI
|
|
778
|
+
|
|
779
|
+
Build behavioral world models from mission, skills, values, and emergent overlap effects.
|
|
780
|
+
|
|
781
|
+
A `.worldmodel.md` file defines three layers:
|
|
782
|
+
|
|
783
|
+
1. **Core Model Geometry** — mission, domains (each carrying skills + values), overlap effects, center identity
|
|
784
|
+
2. **Contextual Modifiers** — authority layers, spatial contexts, interpretation rules
|
|
785
|
+
3. **Evolution Layer** — aligned/drift behaviors, signals, decision priorities, evolution conditions
|
|
786
|
+
|
|
787
|
+
The compiler transforms this into executable governance artifacts:
|
|
788
|
+
|
|
789
|
+
```bash
|
|
790
|
+
# Scaffold a new behavioral model
|
|
791
|
+
neuroverse worldmodel init --name "My Model"
|
|
792
|
+
|
|
793
|
+
# Validate structure and completeness
|
|
794
|
+
neuroverse worldmodel validate ./my-model.worldmodel.md
|
|
795
|
+
|
|
796
|
+
# Human-readable model summary
|
|
797
|
+
neuroverse worldmodel explain ./my-model.worldmodel.md
|
|
798
|
+
|
|
799
|
+
# Compile to .nv-world.md + signals + overlaps + contexts + lenses
|
|
800
|
+
neuroverse worldmodel build ./my-model.worldmodel.md --output ./world/
|
|
801
|
+
|
|
802
|
+
# Emit individual artifacts
|
|
803
|
+
neuroverse worldmodel emit-world ./my-model.worldmodel.md
|
|
804
|
+
neuroverse worldmodel emit-signals ./my-model.worldmodel.md
|
|
805
|
+
neuroverse worldmodel emit-lenses ./my-model.worldmodel.md
|
|
806
|
+
neuroverse worldmodel emit-contexts ./my-model.worldmodel.md
|
|
807
|
+
neuroverse worldmodel emit-overlaps ./my-model.worldmodel.md
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
Example `.worldmodel.md`:
|
|
811
|
+
|
|
812
|
+
```markdown
|
|
813
|
+
---
|
|
814
|
+
name: Auki Vanguard
|
|
815
|
+
version: 1.0.0
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
# Core Model Geometry
|
|
819
|
+
|
|
820
|
+
## Mission
|
|
821
|
+
Build the real world web while preserving long-term mission alignment.
|
|
822
|
+
|
|
823
|
+
## Domains
|
|
824
|
+
|
|
825
|
+
### Future Foresight
|
|
826
|
+
#### Skills
|
|
827
|
+
- Strategic Thinking
|
|
828
|
+
- Systems Design
|
|
829
|
+
#### Values
|
|
830
|
+
- Long-term thinking
|
|
831
|
+
- Intellectual honesty
|
|
832
|
+
|
|
833
|
+
### Narrative Dynamics
|
|
834
|
+
#### Skills
|
|
835
|
+
- Storytelling
|
|
836
|
+
- Communication Design
|
|
837
|
+
#### Values
|
|
838
|
+
- Authenticity
|
|
839
|
+
- Clarity
|
|
840
|
+
|
|
841
|
+
## Overlap Effects
|
|
842
|
+
- Future Foresight + Narrative Dynamics = Inspiration
|
|
843
|
+
|
|
844
|
+
## Center Identity
|
|
845
|
+
Collective Vanguard Leader
|
|
846
|
+
|
|
847
|
+
# Contextual Modifiers
|
|
848
|
+
|
|
849
|
+
## Authority Layers
|
|
850
|
+
- founder
|
|
851
|
+
- contributor
|
|
852
|
+
- agent
|
|
853
|
+
|
|
854
|
+
## Spatial Contexts
|
|
855
|
+
- strategy
|
|
856
|
+
- execution
|
|
857
|
+
- deployment
|
|
858
|
+
|
|
859
|
+
## Interpretation Rules
|
|
860
|
+
- ambiguity from a founder carries more system-wide risk than from a contributor
|
|
861
|
+
|
|
862
|
+
# Evolution Layer
|
|
863
|
+
|
|
864
|
+
## Aligned Behaviors
|
|
865
|
+
- communicates future direction in ways others can act on
|
|
866
|
+
|
|
867
|
+
## Drift Behaviors
|
|
868
|
+
- mission language disconnected from execution
|
|
869
|
+
|
|
870
|
+
## Signals
|
|
871
|
+
- clarity
|
|
872
|
+
- ownership
|
|
873
|
+
- follow_through
|
|
874
|
+
|
|
875
|
+
## Decision Priorities
|
|
876
|
+
- long_term_ecosystem > short_term_convenience
|
|
877
|
+
|
|
878
|
+
## Evolution Conditions
|
|
879
|
+
- propose model updates when repeated behavior contradicts a current assumption
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
The deterministic compiler produces:
|
|
883
|
+
- **`.nv-world.md`** — executable world file (thesis, invariants, state, rules, gates, outcomes, lenses)
|
|
884
|
+
- **`signals.json`** — signal schema for behavioral tracking
|
|
885
|
+
- **`overlaps.json`** — overlap map with pairwise domain effects and matrix view
|
|
886
|
+
- **`contexts.json`** — contextual modifiers for interpretation shaping
|
|
887
|
+
- **`lenses.json`** — lens suggestions derived from overlap effects
|
|
888
|
+
|
|
889
|
+
Two bundled examples ship with the package: `auki-vanguard.worldmodel.md` and `neuroverse-governance.worldmodel.md`.
|
|
890
|
+
|
|
773
891
|
---
|
|
774
892
|
|
|
775
893
|
## Architecture
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLens
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TCGGED4G.js";
|
|
4
4
|
import {
|
|
5
5
|
loadWorld
|
|
6
6
|
} from "./chunk-I4RTIMLX.js";
|
|
@@ -859,55 +859,332 @@ async function fetchNotionAPI(url, headers, init) {
|
|
|
859
859
|
return await res.json();
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
-
// src/radiant/core/
|
|
863
|
-
import { existsSync,
|
|
864
|
-
import { join, resolve
|
|
862
|
+
// src/radiant/core/git-remote.ts
|
|
863
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
864
|
+
import { join, resolve } from "path";
|
|
865
|
+
function resolveGitConfigPath(repoDir) {
|
|
866
|
+
const dotGit = join(repoDir, ".git");
|
|
867
|
+
if (!existsSync(dotGit)) return null;
|
|
868
|
+
try {
|
|
869
|
+
const stat = statSync(dotGit);
|
|
870
|
+
if (stat.isDirectory()) {
|
|
871
|
+
return join(dotGit, "config");
|
|
872
|
+
}
|
|
873
|
+
if (stat.isFile()) {
|
|
874
|
+
const content = readFileSync(dotGit, "utf-8");
|
|
875
|
+
const match = /^gitdir:\s*(.+)$/m.exec(content);
|
|
876
|
+
if (!match) return null;
|
|
877
|
+
const gitDir = resolve(repoDir, match[1].trim());
|
|
878
|
+
const configPath = join(gitDir, "config");
|
|
879
|
+
return existsSync(configPath) ? configPath : null;
|
|
880
|
+
}
|
|
881
|
+
} catch {
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
function readOriginRemote(repoDir) {
|
|
887
|
+
const configPath = resolveGitConfigPath(repoDir);
|
|
888
|
+
if (!configPath) return null;
|
|
889
|
+
try {
|
|
890
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
891
|
+
const sectionRe = /\[remote "origin"\]\s*\n((?:(?!\[)[^\n]*\n?)*)/;
|
|
892
|
+
const section = sectionRe.exec(raw);
|
|
893
|
+
if (!section) return null;
|
|
894
|
+
const urlRe = /^\s*url\s*=\s*(.+?)\s*$/m;
|
|
895
|
+
const url = urlRe.exec(section[1]);
|
|
896
|
+
return url ? url[1] : null;
|
|
897
|
+
} catch {
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
function parseRemoteUrl(url) {
|
|
902
|
+
const trimmed = url.trim();
|
|
903
|
+
if (!trimmed) return null;
|
|
904
|
+
const ssh = /^git@([^:]+):([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
905
|
+
if (ssh) return { host: ssh[1], owner: ssh[2], repo: ssh[3] };
|
|
906
|
+
const sshProto = /^ssh:\/\/git@([^/]+)\/([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
907
|
+
if (sshProto) return { host: sshProto[1], owner: sshProto[2], repo: sshProto[3] };
|
|
908
|
+
const https = /^https?:\/\/(?:[^@/]+@)?([^/]+)\/([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
909
|
+
if (https) return { host: https[1], owner: https[2], repo: https[3] };
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
function getRepoOrigin(repoDir) {
|
|
913
|
+
const url = readOriginRemote(repoDir);
|
|
914
|
+
if (!url) return null;
|
|
915
|
+
return parseRemoteUrl(url);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// src/radiant/core/extends.ts
|
|
919
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, statSync as statSync2, writeFileSync } from "fs";
|
|
920
|
+
import { join as join2, resolve as resolve2, isAbsolute } from "path";
|
|
865
921
|
import { homedir } from "os";
|
|
922
|
+
import { createHash } from "crypto";
|
|
923
|
+
import { execFileSync } from "child_process";
|
|
924
|
+
function loadExtendsConfig(repoDir) {
|
|
925
|
+
const configPath = join2(repoDir, ".neuroverse", "config.json");
|
|
926
|
+
if (!existsSync2(configPath)) return null;
|
|
927
|
+
try {
|
|
928
|
+
const raw = readFileSync2(configPath, "utf-8");
|
|
929
|
+
const parsed = JSON.parse(raw);
|
|
930
|
+
return parsed;
|
|
931
|
+
} catch {
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
function parseExtendsSpec(raw) {
|
|
936
|
+
const trimmed = raw.trim();
|
|
937
|
+
if (!trimmed) return null;
|
|
938
|
+
if (trimmed.startsWith("github:")) {
|
|
939
|
+
const rest = trimmed.slice("github:".length);
|
|
940
|
+
const match = /^([^/]+)\/([^@:]+)(?:@([^:]+))?(?::(.+))?$/.exec(rest);
|
|
941
|
+
if (!match) return null;
|
|
942
|
+
return {
|
|
943
|
+
raw: trimmed,
|
|
944
|
+
kind: "github",
|
|
945
|
+
owner: match[1],
|
|
946
|
+
repo: match[2],
|
|
947
|
+
ref: match[3] ?? "HEAD",
|
|
948
|
+
subpath: match[4] ?? ""
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("../") || isAbsolute(trimmed)) {
|
|
952
|
+
return { raw: trimmed, kind: "local", path: trimmed };
|
|
953
|
+
}
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
957
|
+
function getCacheDir(spec, baseCacheDir) {
|
|
958
|
+
const root = baseCacheDir ?? join2(homedir(), ".neuroverse", "cache", "extends");
|
|
959
|
+
const key = createHash("sha256").update(spec.raw).digest("hex").slice(0, 16);
|
|
960
|
+
return join2(root, key);
|
|
961
|
+
}
|
|
962
|
+
function isCacheFresh(cacheDir, ttlMs) {
|
|
963
|
+
const stampPath = join2(cacheDir, ".neuroverse-fetched");
|
|
964
|
+
if (!existsSync2(stampPath)) return false;
|
|
965
|
+
try {
|
|
966
|
+
const stamp = statSync2(stampPath);
|
|
967
|
+
return Date.now() - stamp.mtimeMs < ttlMs;
|
|
968
|
+
} catch {
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function markCacheFresh(cacheDir) {
|
|
973
|
+
const stampPath = join2(cacheDir, ".neuroverse-fetched");
|
|
974
|
+
try {
|
|
975
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
976
|
+
writeFileSync(stampPath, (/* @__PURE__ */ new Date()).toISOString());
|
|
977
|
+
} catch {
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
var defaultGitFetcher = (spec, destDir) => {
|
|
981
|
+
if (spec.kind !== "github") return;
|
|
982
|
+
const url = `https://github.com/${spec.owner}/${spec.repo}.git`;
|
|
983
|
+
const parent = resolve2(destDir, "..");
|
|
984
|
+
mkdirSync(parent, { recursive: true });
|
|
985
|
+
if (existsSync2(destDir)) {
|
|
986
|
+
rmSync(destDir, { recursive: true, force: true });
|
|
987
|
+
}
|
|
988
|
+
const args = ["clone", "--depth", "1", "--filter=blob:none"];
|
|
989
|
+
if (spec.ref && spec.ref !== "HEAD") {
|
|
990
|
+
args.push("--branch", spec.ref);
|
|
991
|
+
}
|
|
992
|
+
args.push(url, destDir);
|
|
993
|
+
execFileSync("git", args, { stdio: "pipe" });
|
|
994
|
+
};
|
|
995
|
+
function resolveExtendsSpec(spec, repoDir, options) {
|
|
996
|
+
if (spec.kind === "local") {
|
|
997
|
+
const full = isAbsolute(spec.path) ? spec.path : resolve2(repoDir, spec.path);
|
|
998
|
+
if (!existsSync2(full)) {
|
|
999
|
+
return { spec, dir: null, warning: `local extends path not found: ${full}` };
|
|
1000
|
+
}
|
|
1001
|
+
return { spec, dir: full };
|
|
1002
|
+
}
|
|
1003
|
+
const cacheRoot = options?.cacheDir;
|
|
1004
|
+
const ttl = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1005
|
+
const cacheDir = getCacheDir(spec, cacheRoot);
|
|
1006
|
+
const fresh = isCacheFresh(cacheDir, ttl);
|
|
1007
|
+
const needsFetch = options?.forceRefresh || !fresh || !existsSync2(cacheDir);
|
|
1008
|
+
if (needsFetch && options?.noFetch) {
|
|
1009
|
+
if (existsSync2(cacheDir) && existsSync2(join2(cacheDir, ".neuroverse-fetched"))) {
|
|
1010
|
+
return resolveSubpath(spec, cacheDir);
|
|
1011
|
+
}
|
|
1012
|
+
return options?.silentOnMissing ? { spec, dir: null } : { spec, dir: null, warning: `NEUROVERSE_NO_FETCH set and no cache for ${spec.raw}` };
|
|
1013
|
+
}
|
|
1014
|
+
if (needsFetch) {
|
|
1015
|
+
const fetcher = options?.fetcher ?? defaultGitFetcher;
|
|
1016
|
+
try {
|
|
1017
|
+
fetcher(spec, cacheDir);
|
|
1018
|
+
markCacheFresh(cacheDir);
|
|
1019
|
+
} catch (err) {
|
|
1020
|
+
if (existsSync2(cacheDir) && existsSync2(join2(cacheDir, ".neuroverse-fetched"))) {
|
|
1021
|
+
const result = resolveSubpath(spec, cacheDir);
|
|
1022
|
+
return options?.silentOnMissing ? result : { ...result, warning: `fetch failed for ${spec.raw}, using stale cache: ${err.message}` };
|
|
1023
|
+
}
|
|
1024
|
+
return options?.silentOnMissing ? { spec, dir: null } : { spec, dir: null, warning: `fetch failed for ${spec.raw}: ${err.message}` };
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return resolveSubpath(spec, cacheDir);
|
|
1028
|
+
}
|
|
1029
|
+
function resolveSubpath(spec, cacheDir) {
|
|
1030
|
+
const target = spec.subpath ? join2(cacheDir, spec.subpath) : cacheDir;
|
|
1031
|
+
if (!existsSync2(target)) {
|
|
1032
|
+
return { spec, dir: null, warning: `subpath not found in ${spec.raw}: ${spec.subpath}` };
|
|
1033
|
+
}
|
|
1034
|
+
if (!spec.subpath) {
|
|
1035
|
+
const candidates = [
|
|
1036
|
+
join2(target, "worlds"),
|
|
1037
|
+
join2(target, ".neuroverse", "worlds")
|
|
1038
|
+
];
|
|
1039
|
+
for (const c of candidates) {
|
|
1040
|
+
if (existsSync2(c)) return { spec, dir: c };
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return { spec, dir: target };
|
|
1044
|
+
}
|
|
1045
|
+
function detectOrgExtendsSpec(repoDir) {
|
|
1046
|
+
const origin = getRepoOrigin(repoDir);
|
|
1047
|
+
if (!origin) return null;
|
|
1048
|
+
if (origin.host !== "github.com") return null;
|
|
1049
|
+
if (origin.repo === "worlds") return null;
|
|
1050
|
+
return {
|
|
1051
|
+
raw: `github:${origin.owner}/worlds`,
|
|
1052
|
+
kind: "github",
|
|
1053
|
+
owner: origin.owner,
|
|
1054
|
+
repo: "worlds",
|
|
1055
|
+
ref: "HEAD",
|
|
1056
|
+
subpath: ""
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
function resolveAllExtends(repoDir, options) {
|
|
1060
|
+
const config = options?.config !== void 0 ? options.config : loadExtendsConfig(repoDir);
|
|
1061
|
+
if (!config?.extends || config.extends.length === 0) return [];
|
|
1062
|
+
const results = [];
|
|
1063
|
+
for (const raw of config.extends) {
|
|
1064
|
+
const spec = parseExtendsSpec(raw);
|
|
1065
|
+
if (!spec) {
|
|
1066
|
+
results.push({
|
|
1067
|
+
spec: { raw, kind: "local" },
|
|
1068
|
+
dir: null,
|
|
1069
|
+
warning: `unparseable extends spec: ${raw}`
|
|
1070
|
+
});
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
results.push(resolveExtendsSpec(spec, repoDir, options));
|
|
1074
|
+
}
|
|
1075
|
+
return results;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// src/radiant/core/discovery.ts
|
|
1079
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
1080
|
+
import { join as join3, resolve as resolve3, basename } from "path";
|
|
1081
|
+
import { homedir as homedir2 } from "os";
|
|
866
1082
|
function discoverWorlds(options) {
|
|
867
1083
|
const worlds = [];
|
|
868
|
-
const
|
|
869
|
-
|
|
1084
|
+
const warnings = [];
|
|
1085
|
+
const forceRefresh = process.env.NEUROVERSE_REFRESH === "1";
|
|
1086
|
+
const noFetch = process.env.NEUROVERSE_NO_FETCH === "1";
|
|
1087
|
+
const noOrg = options?.disableOrg || process.env.NEUROVERSE_NO_ORG === "1";
|
|
1088
|
+
const userDir = options?.userWorldsDir ?? join3(homedir2(), ".neuroverse", "worlds");
|
|
1089
|
+
if (existsSync3(userDir)) {
|
|
870
1090
|
worlds.push(...loadWorldsFromDir(userDir, "user"));
|
|
871
1091
|
}
|
|
1092
|
+
if (!noOrg && !options?.explicitWorldsDir) {
|
|
1093
|
+
const specs = [];
|
|
1094
|
+
if (options?.repoDir) {
|
|
1095
|
+
const fromGit = detectOrgExtendsSpec(options.repoDir);
|
|
1096
|
+
if (fromGit) specs.push(fromGit);
|
|
1097
|
+
}
|
|
1098
|
+
if (options?.scopeOwner) {
|
|
1099
|
+
const already = specs.some(
|
|
1100
|
+
(s) => s.owner?.toLowerCase() === options.scopeOwner.toLowerCase()
|
|
1101
|
+
);
|
|
1102
|
+
if (!already) {
|
|
1103
|
+
specs.push({
|
|
1104
|
+
raw: `github:${options.scopeOwner}/worlds`,
|
|
1105
|
+
kind: "github",
|
|
1106
|
+
owner: options.scopeOwner,
|
|
1107
|
+
repo: "worlds"
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
const baseDir = options?.repoDir ?? process.cwd();
|
|
1112
|
+
for (const spec of specs) {
|
|
1113
|
+
const result = resolveExtendsSpec(spec, baseDir, {
|
|
1114
|
+
cacheDir: options?.extendsCacheDir,
|
|
1115
|
+
fetcher: options?.extendsFetcher,
|
|
1116
|
+
ttlMs: options?.extendsTtlMs,
|
|
1117
|
+
forceRefresh,
|
|
1118
|
+
noFetch,
|
|
1119
|
+
silentOnMissing: true
|
|
1120
|
+
});
|
|
1121
|
+
worlds.push(...loadExtendsWorlds(result, "org"));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
if (options?.repoDir && !options.disableExtends && !options.explicitWorldsDir) {
|
|
1125
|
+
const results = resolveAllExtends(options.repoDir, {
|
|
1126
|
+
cacheDir: options.extendsCacheDir,
|
|
1127
|
+
fetcher: options.extendsFetcher,
|
|
1128
|
+
ttlMs: options.extendsTtlMs,
|
|
1129
|
+
forceRefresh,
|
|
1130
|
+
noFetch
|
|
1131
|
+
});
|
|
1132
|
+
for (const result of results) {
|
|
1133
|
+
worlds.push(...loadExtendsWorlds(result, "extends"));
|
|
1134
|
+
if (result.warning) warnings.push(result.warning);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
872
1137
|
if (options?.explicitWorldsDir) {
|
|
873
1138
|
worlds.push(...loadWorldsFromDir(options.explicitWorldsDir, "repo"));
|
|
874
1139
|
} else if (options?.repoDir) {
|
|
875
1140
|
const repoPaths = [
|
|
876
|
-
|
|
877
|
-
|
|
1141
|
+
join3(options.repoDir, "worlds"),
|
|
1142
|
+
join3(options.repoDir, ".neuroverse", "worlds")
|
|
878
1143
|
];
|
|
879
1144
|
for (const p of repoPaths) {
|
|
880
|
-
if (
|
|
1145
|
+
if (existsSync3(p)) {
|
|
881
1146
|
worlds.push(...loadWorldsFromDir(p, "repo"));
|
|
882
1147
|
break;
|
|
883
1148
|
}
|
|
884
1149
|
}
|
|
885
1150
|
}
|
|
886
|
-
const combinedContent = worlds.map((w) =>
|
|
887
|
-
${w.
|
|
1151
|
+
const combinedContent = worlds.map((w) => {
|
|
1152
|
+
const tag = w.extendsFrom ? `<!-- world: ${w.name} (${w.source} ${w.extendsFrom}) -->` : `<!-- world: ${w.name} (${w.source}) -->`;
|
|
1153
|
+
return `${tag}
|
|
1154
|
+
${w.content}`;
|
|
1155
|
+
}).join("\n\n---\n\n");
|
|
888
1156
|
const summary = worlds.length === 0 ? "no worlds discovered" : worlds.map((w) => `${w.name} (${w.source})`).join(", ");
|
|
889
|
-
return { worlds, combinedContent, summary };
|
|
1157
|
+
return { worlds, combinedContent, summary, warnings };
|
|
890
1158
|
}
|
|
891
1159
|
function formatActiveWorlds(stack) {
|
|
892
1160
|
if (stack.worlds.length === 0) return "No worlds loaded.";
|
|
893
1161
|
const lines = ["ACTIVE WORLDS", ""];
|
|
894
1162
|
for (const w of stack.worlds) {
|
|
895
|
-
const sourceLabel = w.source === "base" ? "universal" : w.source === "user" ? "personal" : "this repo";
|
|
1163
|
+
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";
|
|
896
1164
|
lines.push(` ${w.name} (${sourceLabel})`);
|
|
897
1165
|
}
|
|
1166
|
+
if (stack.warnings.length > 0) {
|
|
1167
|
+
lines.push("", "WARNINGS");
|
|
1168
|
+
for (const w of stack.warnings) lines.push(` ${w}`);
|
|
1169
|
+
}
|
|
898
1170
|
return lines.join("\n");
|
|
899
1171
|
}
|
|
1172
|
+
function loadExtendsWorlds(result, source) {
|
|
1173
|
+
if (!result.dir) return [];
|
|
1174
|
+
const loaded = loadWorldsFromDir(result.dir, source);
|
|
1175
|
+
return loaded.map((w) => ({ ...w, extendsFrom: result.spec.raw }));
|
|
1176
|
+
}
|
|
900
1177
|
function loadWorldsFromDir(dirPath, source) {
|
|
901
|
-
const dir =
|
|
902
|
-
if (!
|
|
903
|
-
const stat =
|
|
1178
|
+
const dir = resolve3(dirPath);
|
|
1179
|
+
if (!existsSync3(dir)) return [];
|
|
1180
|
+
const stat = statSync3(dir);
|
|
904
1181
|
if (stat.isFile() && dir.endsWith(".md")) {
|
|
905
1182
|
try {
|
|
906
1183
|
return [{
|
|
907
1184
|
name: basename(dir).replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
908
1185
|
source,
|
|
909
1186
|
path: dir,
|
|
910
|
-
content:
|
|
1187
|
+
content: readFileSync3(dir, "utf-8")
|
|
911
1188
|
}];
|
|
912
1189
|
} catch {
|
|
913
1190
|
return [];
|
|
@@ -918,28 +1195,28 @@ function loadWorldsFromDir(dirPath, source) {
|
|
|
918
1195
|
(f) => f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md")
|
|
919
1196
|
).sort();
|
|
920
1197
|
return files.map((f) => {
|
|
921
|
-
const fullPath =
|
|
1198
|
+
const fullPath = join3(dir, f);
|
|
922
1199
|
return {
|
|
923
1200
|
name: f.replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
924
1201
|
source,
|
|
925
1202
|
path: fullPath,
|
|
926
|
-
content:
|
|
1203
|
+
content: readFileSync3(fullPath, "utf-8")
|
|
927
1204
|
};
|
|
928
1205
|
});
|
|
929
1206
|
}
|
|
930
1207
|
|
|
931
1208
|
// src/radiant/adapters/exocortex.ts
|
|
932
|
-
import { readFileSync as
|
|
933
|
-
import { join as
|
|
1209
|
+
import { readFileSync as readFileSync4, existsSync as existsSync4, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
1210
|
+
import { join as join4, resolve as resolve4 } from "path";
|
|
934
1211
|
function readExocortex(dirPath, repoName) {
|
|
935
|
-
const dir =
|
|
1212
|
+
const dir = resolve4(dirPath);
|
|
936
1213
|
let filesLoaded = 0;
|
|
937
1214
|
function tryRead(...paths) {
|
|
938
1215
|
for (const p of paths) {
|
|
939
|
-
const full =
|
|
940
|
-
if (
|
|
1216
|
+
const full = join4(dir, p);
|
|
1217
|
+
if (existsSync4(full)) {
|
|
941
1218
|
try {
|
|
942
|
-
const content =
|
|
1219
|
+
const content = readFileSync4(full, "utf-8").trim();
|
|
943
1220
|
if (content) {
|
|
944
1221
|
filesLoaded++;
|
|
945
1222
|
return content;
|
|
@@ -1049,14 +1326,14 @@ ${ctx.methods}`);
|
|
|
1049
1326
|
return sections.join("\n\n");
|
|
1050
1327
|
}
|
|
1051
1328
|
function readTeamExocortices(teamDir) {
|
|
1052
|
-
const dir =
|
|
1053
|
-
if (!
|
|
1329
|
+
const dir = resolve4(teamDir);
|
|
1330
|
+
if (!existsSync4(dir)) return [];
|
|
1054
1331
|
const entries = readdirSync2(dir);
|
|
1055
1332
|
const results = [];
|
|
1056
1333
|
for (const entry of entries) {
|
|
1057
|
-
const entryPath =
|
|
1334
|
+
const entryPath = join4(dir, entry);
|
|
1058
1335
|
try {
|
|
1059
|
-
const stat =
|
|
1336
|
+
const stat = statSync4(entryPath);
|
|
1060
1337
|
if (stat.isDirectory()) {
|
|
1061
1338
|
const ctx = readExocortex(entryPath);
|
|
1062
1339
|
if (ctx.filesLoaded > 0) {
|
|
@@ -1101,25 +1378,25 @@ function summarizeExocortex(ctx) {
|
|
|
1101
1378
|
}
|
|
1102
1379
|
|
|
1103
1380
|
// src/radiant/memory/palace.ts
|
|
1104
|
-
import { readFileSync as
|
|
1105
|
-
import { join as
|
|
1381
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync3, existsSync as existsSync5 } from "fs";
|
|
1382
|
+
import { join as join5, resolve as resolve5 } from "path";
|
|
1106
1383
|
function writeRead(exocortexDir, frontmatter, text) {
|
|
1107
|
-
const dir =
|
|
1108
|
-
|
|
1384
|
+
const dir = resolve5(exocortexDir, "radiant", "reads");
|
|
1385
|
+
mkdirSync2(dir, { recursive: true });
|
|
1109
1386
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1110
1387
|
const filename = `${date}.md`;
|
|
1111
|
-
const filepath =
|
|
1388
|
+
const filepath = join5(dir, filename);
|
|
1112
1389
|
const content = `${frontmatter}
|
|
1113
1390
|
|
|
1114
1391
|
${text}
|
|
1115
1392
|
`;
|
|
1116
|
-
|
|
1393
|
+
writeFileSync2(filepath, content, "utf-8");
|
|
1117
1394
|
return filepath;
|
|
1118
1395
|
}
|
|
1119
1396
|
function updateKnowledge(exocortexDir, persistence, options) {
|
|
1120
|
-
const dir =
|
|
1121
|
-
|
|
1122
|
-
const filepath =
|
|
1397
|
+
const dir = resolve5(exocortexDir, "radiant");
|
|
1398
|
+
mkdirSync2(dir, { recursive: true });
|
|
1399
|
+
const filepath = join5(dir, "knowledge.md");
|
|
1123
1400
|
const totalReads = options?.totalReads ?? 0;
|
|
1124
1401
|
const existingUntriggered = loadUntriggeredCounts(filepath);
|
|
1125
1402
|
const lines = [
|
|
@@ -1206,14 +1483,14 @@ function updateKnowledge(exocortexDir, persistence, options) {
|
|
|
1206
1483
|
lines.push(`${name}=${count}`);
|
|
1207
1484
|
}
|
|
1208
1485
|
lines.push("-->");
|
|
1209
|
-
|
|
1486
|
+
writeFileSync2(filepath, lines.join("\n"), "utf-8");
|
|
1210
1487
|
return filepath;
|
|
1211
1488
|
}
|
|
1212
1489
|
function loadUntriggeredCounts(filepath) {
|
|
1213
1490
|
const counts = /* @__PURE__ */ new Map();
|
|
1214
|
-
if (!
|
|
1491
|
+
if (!existsSync5(filepath)) return counts;
|
|
1215
1492
|
try {
|
|
1216
|
-
const content =
|
|
1493
|
+
const content = readFileSync5(filepath, "utf-8");
|
|
1217
1494
|
const match = content.match(
|
|
1218
1495
|
/<!-- untriggered_counts[\s\S]*?-->/
|
|
1219
1496
|
);
|
|
@@ -1231,13 +1508,13 @@ function loadUntriggeredCounts(filepath) {
|
|
|
1231
1508
|
return counts;
|
|
1232
1509
|
}
|
|
1233
1510
|
function loadPriorReads(exocortexDir) {
|
|
1234
|
-
const dir =
|
|
1235
|
-
if (!
|
|
1511
|
+
const dir = resolve5(exocortexDir, "radiant", "reads");
|
|
1512
|
+
if (!existsSync5(dir)) return [];
|
|
1236
1513
|
const files = readdirSync3(dir).filter((f) => f.endsWith(".md")).sort();
|
|
1237
1514
|
const reads = [];
|
|
1238
1515
|
for (const filename of files) {
|
|
1239
|
-
const filepath =
|
|
1240
|
-
const content =
|
|
1516
|
+
const filepath = join5(dir, filename);
|
|
1517
|
+
const content = readFileSync5(filepath, "utf-8");
|
|
1241
1518
|
const date = filename.replace(".md", "");
|
|
1242
1519
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1243
1520
|
const frontmatter = fmMatch ? fmMatch[1] : "";
|
|
@@ -2283,6 +2560,15 @@ export {
|
|
|
2283
2560
|
formatSlackSignalsForPrompt,
|
|
2284
2561
|
fetchNotionActivity,
|
|
2285
2562
|
formatNotionSignalsForPrompt,
|
|
2563
|
+
readOriginRemote,
|
|
2564
|
+
parseRemoteUrl,
|
|
2565
|
+
getRepoOrigin,
|
|
2566
|
+
loadExtendsConfig,
|
|
2567
|
+
parseExtendsSpec,
|
|
2568
|
+
getCacheDir,
|
|
2569
|
+
resolveExtendsSpec,
|
|
2570
|
+
detectOrgExtendsSpec,
|
|
2571
|
+
resolveAllExtends,
|
|
2286
2572
|
discoverWorlds,
|
|
2287
2573
|
formatActiveWorlds,
|
|
2288
2574
|
readExocortex,
|