@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 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
- Three ways to create a world. All produce the same `WorldDefinition` object:
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-F2LWMOM5.js";
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/discovery.ts
863
- import { existsSync, readdirSync, readFileSync, statSync } from "fs";
864
- import { join, resolve, basename } from "path";
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 userDir = options?.userWorldsDir ?? join(homedir(), ".neuroverse", "worlds");
869
- if (existsSync(userDir)) {
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
- join(options.repoDir, "worlds"),
877
- join(options.repoDir, ".neuroverse", "worlds")
1141
+ join3(options.repoDir, "worlds"),
1142
+ join3(options.repoDir, ".neuroverse", "worlds")
878
1143
  ];
879
1144
  for (const p of repoPaths) {
880
- if (existsSync(p)) {
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) => `<!-- world: ${w.name} (${w.source}) -->
887
- ${w.content}`).join("\n\n---\n\n");
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 = resolve(dirPath);
902
- if (!existsSync(dir)) return [];
903
- const stat = statSync(dir);
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: readFileSync(dir, "utf-8")
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 = join(dir, f);
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: readFileSync(fullPath, "utf-8")
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 readFileSync2, existsSync as existsSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
933
- import { join as join2, resolve as resolve2 } from "path";
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 = resolve2(dirPath);
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 = join2(dir, p);
940
- if (existsSync2(full)) {
1216
+ const full = join4(dir, p);
1217
+ if (existsSync4(full)) {
941
1218
  try {
942
- const content = readFileSync2(full, "utf-8").trim();
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 = resolve2(teamDir);
1053
- if (!existsSync2(dir)) return [];
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 = join2(dir, entry);
1334
+ const entryPath = join4(dir, entry);
1058
1335
  try {
1059
- const stat = statSync2(entryPath);
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 readFileSync3, writeFileSync, mkdirSync, readdirSync as readdirSync3, existsSync as existsSync3 } from "fs";
1105
- import { join as join3, resolve as resolve3 } from "path";
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 = resolve3(exocortexDir, "radiant", "reads");
1108
- mkdirSync(dir, { recursive: true });
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 = join3(dir, filename);
1388
+ const filepath = join5(dir, filename);
1112
1389
  const content = `${frontmatter}
1113
1390
 
1114
1391
  ${text}
1115
1392
  `;
1116
- writeFileSync(filepath, content, "utf-8");
1393
+ writeFileSync2(filepath, content, "utf-8");
1117
1394
  return filepath;
1118
1395
  }
1119
1396
  function updateKnowledge(exocortexDir, persistence, options) {
1120
- const dir = resolve3(exocortexDir, "radiant");
1121
- mkdirSync(dir, { recursive: true });
1122
- const filepath = join3(dir, "knowledge.md");
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
- writeFileSync(filepath, lines.join("\n"), "utf-8");
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 (!existsSync3(filepath)) return counts;
1491
+ if (!existsSync5(filepath)) return counts;
1215
1492
  try {
1216
- const content = readFileSync3(filepath, "utf-8");
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 = resolve3(exocortexDir, "radiant", "reads");
1235
- if (!existsSync3(dir)) return [];
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 = join3(dir, filename);
1240
- const content = readFileSync3(filepath, "utf-8");
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,