@neuroverseos/governance 0.8.1 → 0.10.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 +120 -2
- package/dist/{chunk-ETDIEVAX.js → chunk-BZYQHJDM.js} +800 -54
- package/dist/{chunk-F2LWMOM5.js → chunk-TCGGED4G.js} +14 -14
- package/dist/cli/neuroverse.cjs +1362 -219
- package/dist/cli/radiant.cjs +1212 -116
- package/dist/cli/radiant.d.cts +44 -1
- package/dist/cli/radiant.d.ts +44 -1
- package/dist/cli/radiant.js +354 -28
- 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 +826 -62
- package/dist/radiant/index.d.cts +304 -19
- package/dist/radiant/index.d.ts +304 -19
- package/dist/radiant/index.js +30 -2
- package/dist/{server-ZSQ6DRSN.js → server-EI5JCIBU.js} +2 -2
- package/examples/radiant-weekly-workflow.yml +84 -0
- package/package.json +2 -1
package/dist/cli/radiant.cjs
CHANGED
|
@@ -477,7 +477,7 @@ function sovereignConduitRewrite(pattern) {
|
|
|
477
477
|
return {
|
|
478
478
|
...pattern,
|
|
479
479
|
framing: "what this means for the people in the system",
|
|
480
|
-
emphasis: "humanity +
|
|
480
|
+
emphasis: "humanity + agency + learning",
|
|
481
481
|
compress: false
|
|
482
482
|
};
|
|
483
483
|
}
|
|
@@ -488,17 +488,17 @@ var init_sovereign_conduit = __esm({
|
|
|
488
488
|
SOVEREIGN_CONDUIT_FRAME = {
|
|
489
489
|
domains: [
|
|
490
490
|
"stewardship",
|
|
491
|
-
"
|
|
491
|
+
"agency",
|
|
492
492
|
"integration"
|
|
493
493
|
],
|
|
494
494
|
overlaps: [
|
|
495
495
|
{
|
|
496
|
-
domains: ["stewardship", "
|
|
496
|
+
domains: ["stewardship", "agency"],
|
|
497
497
|
emergent_state: "Trust",
|
|
498
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
499
|
},
|
|
500
500
|
{
|
|
501
|
-
domains: ["
|
|
501
|
+
domains: ["agency", "integration"],
|
|
502
502
|
emergent_state: "Possibility",
|
|
503
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
504
|
},
|
|
@@ -529,7 +529,7 @@ var init_sovereign_conduit = __esm({
|
|
|
529
529
|
"harm detection",
|
|
530
530
|
"constraint design"
|
|
531
531
|
],
|
|
532
|
-
"
|
|
532
|
+
"agency": [
|
|
533
533
|
"independent thinking",
|
|
534
534
|
"decision ownership",
|
|
535
535
|
"self-trust",
|
|
@@ -553,7 +553,7 @@ var init_sovereign_conduit = __esm({
|
|
|
553
553
|
output_translation: {
|
|
554
554
|
never_surface_in_output: [
|
|
555
555
|
"Stewardship",
|
|
556
|
-
"
|
|
556
|
+
"Agency",
|
|
557
557
|
"Integration"
|
|
558
558
|
],
|
|
559
559
|
surface_freely: [
|
|
@@ -568,7 +568,7 @@ var init_sovereign_conduit = __esm({
|
|
|
568
568
|
external_expression: "the boundaries are clear and the system feels safe to operate inside"
|
|
569
569
|
},
|
|
570
570
|
{
|
|
571
|
-
internal_reasoning: "
|
|
571
|
+
internal_reasoning: "Agency is weakening",
|
|
572
572
|
external_expression: "decision ownership is quietly shifting \u2014 the human is accepting AI output without engaging with it"
|
|
573
573
|
},
|
|
574
574
|
{
|
|
@@ -651,12 +651,12 @@ var init_sovereign_conduit = __esm({
|
|
|
651
651
|
close_with_strategic_frame: "preferred",
|
|
652
652
|
punchline_move: "sparing",
|
|
653
653
|
honesty_about_failure: "required",
|
|
654
|
-
output_translation: `Reason internally through the three-domain frame (Stewardship,
|
|
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
655
|
};
|
|
656
656
|
SOVEREIGN_CONDUIT_FORBIDDEN = Object.freeze([
|
|
657
657
|
// Bucket names as labels
|
|
658
658
|
"stewardship is",
|
|
659
|
-
"
|
|
659
|
+
"agency is",
|
|
660
660
|
"integration is",
|
|
661
661
|
// AI-assistant hedging
|
|
662
662
|
"it may be beneficial to consider",
|
|
@@ -692,7 +692,7 @@ var init_sovereign_conduit = __esm({
|
|
|
692
692
|
"Here's what's actually happening: [plain explanation].",
|
|
693
693
|
"The question to ask yourself: [question].",
|
|
694
694
|
"The difference between [A] and [B] matters here: [why].",
|
|
695
|
-
//
|
|
695
|
+
// Agency checks
|
|
696
696
|
"Are you still the author of this decision, or did the AI make it for you?",
|
|
697
697
|
"The AI extended your thinking here. That's working.",
|
|
698
698
|
"The AI replaced your thinking here. That's the drift to watch.",
|
|
@@ -703,7 +703,7 @@ var init_sovereign_conduit = __esm({
|
|
|
703
703
|
]);
|
|
704
704
|
SOVEREIGN_CONDUIT_STRATEGIC = Object.freeze([
|
|
705
705
|
"Safety before expansion \u2014 always. No exception.",
|
|
706
|
-
"
|
|
706
|
+
"Agency before convenience \u2014 the right to think for yourself is not a feature to optimize away.",
|
|
707
707
|
"Extension, not replacement \u2014 AI should make your thinking bigger, not do your thinking for you.",
|
|
708
708
|
"Diversity over uniformity \u2014 different thinkers produce different ideas, and that's the engine of progress.",
|
|
709
709
|
"The rules should be visible \u2014 like a good house, you know the rules before you walk in.",
|
|
@@ -713,16 +713,16 @@ var init_sovereign_conduit = __esm({
|
|
|
713
713
|
]);
|
|
714
714
|
SOVEREIGN_CONDUIT_EXEMPLARS = Object.freeze([
|
|
715
715
|
{
|
|
716
|
-
path: "neuroverseos-sovereign-conduit.worldmodel.md",
|
|
716
|
+
path: "src/radiant/examples/neuroverse-base/neuroverseos-sovereign-conduit.worldmodel.md",
|
|
717
717
|
title: "The Sovereign Conduit Worldmodel",
|
|
718
|
-
exhibits: ["stewardship", "
|
|
718
|
+
exhibits: ["stewardship", "agency", "integration"],
|
|
719
719
|
integration_quality: "full \u2014 all three domains defined, overlaps named, center identity declared",
|
|
720
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
721
|
}
|
|
722
722
|
]);
|
|
723
723
|
sovereignConduitLens = {
|
|
724
724
|
name: "sovereign-conduit",
|
|
725
|
-
description: "The NeuroVerseOS base lens. Warm, accessible, teaching. Evaluates activity through Stewardship (safety),
|
|
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
726
|
primary_frame: {
|
|
727
727
|
domains: SOVEREIGN_CONDUIT_FRAME.domains,
|
|
728
728
|
overlaps: SOVEREIGN_CONDUIT_FRAME.overlaps,
|
|
@@ -1670,82 +1670,638 @@ var init_notion = __esm({
|
|
|
1670
1670
|
}
|
|
1671
1671
|
});
|
|
1672
1672
|
|
|
1673
|
+
// src/radiant/adapters/linear.ts
|
|
1674
|
+
async function fetchLinearActivity(apiKey, options = {}) {
|
|
1675
|
+
const windowDays = options.windowDays ?? 14;
|
|
1676
|
+
const maxIssues = options.maxIssues ?? 200;
|
|
1677
|
+
const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
|
|
1678
|
+
const sinceIso = since.toISOString();
|
|
1679
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
1680
|
+
const teamFilter = options.teamIds && options.teamIds.length > 0 ? `team: { id: { in: [${options.teamIds.map((t) => JSON.stringify(t)).join(", ")}] } }` : "";
|
|
1681
|
+
const issuesQuery = `
|
|
1682
|
+
query RadiantIssues($since: DateTimeOrDuration!, $first: Int!) {
|
|
1683
|
+
issues(
|
|
1684
|
+
filter: {
|
|
1685
|
+
updatedAt: { gte: $since }
|
|
1686
|
+
${teamFilter}
|
|
1687
|
+
}
|
|
1688
|
+
first: $first
|
|
1689
|
+
orderBy: updatedAt
|
|
1690
|
+
) {
|
|
1691
|
+
nodes {
|
|
1692
|
+
id
|
|
1693
|
+
identifier
|
|
1694
|
+
title
|
|
1695
|
+
url
|
|
1696
|
+
createdAt
|
|
1697
|
+
updatedAt
|
|
1698
|
+
completedAt
|
|
1699
|
+
canceledAt
|
|
1700
|
+
state { name type }
|
|
1701
|
+
assignee { id name email }
|
|
1702
|
+
creator { id name }
|
|
1703
|
+
team { id name }
|
|
1704
|
+
project { id name }
|
|
1705
|
+
cycle { id number startsAt endsAt }
|
|
1706
|
+
comments(first: 20) {
|
|
1707
|
+
nodes { id body createdAt user { id name } }
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
`;
|
|
1713
|
+
const cyclesQuery = `
|
|
1714
|
+
query RadiantCycles($since: DateTimeOrDuration!, $now: DateTimeOrDuration!) {
|
|
1715
|
+
cycles(
|
|
1716
|
+
filter: { endsAt: { gte: $since, lte: $now } }
|
|
1717
|
+
first: 20
|
|
1718
|
+
) {
|
|
1719
|
+
nodes {
|
|
1720
|
+
id
|
|
1721
|
+
number
|
|
1722
|
+
startsAt
|
|
1723
|
+
endsAt
|
|
1724
|
+
issueCountHistory
|
|
1725
|
+
completedIssueCountHistory
|
|
1726
|
+
team { id name }
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
`;
|
|
1731
|
+
const [issuesResponse, cyclesResponse] = await Promise.all([
|
|
1732
|
+
fetchLinearGraphQL(apiKey, issuesQuery, {
|
|
1733
|
+
since: sinceIso,
|
|
1734
|
+
first: maxIssues
|
|
1735
|
+
}),
|
|
1736
|
+
fetchLinearGraphQL(apiKey, cyclesQuery, {
|
|
1737
|
+
since: sinceIso,
|
|
1738
|
+
now: nowIso
|
|
1739
|
+
})
|
|
1740
|
+
]);
|
|
1741
|
+
const rawIssues = issuesResponse.issues?.nodes ?? [];
|
|
1742
|
+
const rawCycles = cyclesResponse.cycles?.nodes ?? [];
|
|
1743
|
+
const events = [];
|
|
1744
|
+
const assignees = /* @__PURE__ */ new Set();
|
|
1745
|
+
const projects = /* @__PURE__ */ new Map();
|
|
1746
|
+
let issuesCreated = 0;
|
|
1747
|
+
let issuesCompleted = 0;
|
|
1748
|
+
let issuesOpen = 0;
|
|
1749
|
+
let issuesStalled = 0;
|
|
1750
|
+
let commentsTotal = 0;
|
|
1751
|
+
const now = Date.now();
|
|
1752
|
+
const stallThresholdMs = 14 * 24 * 60 * 60 * 1e3;
|
|
1753
|
+
for (const issue of rawIssues) {
|
|
1754
|
+
const created = new Date(issue.createdAt);
|
|
1755
|
+
const updated = new Date(issue.updatedAt);
|
|
1756
|
+
const completed = issue.completedAt ? new Date(issue.completedAt) : null;
|
|
1757
|
+
const assigneeId = issue.assignee?.id ?? "unassigned";
|
|
1758
|
+
if (assigneeId !== "unassigned") assignees.add(assigneeId);
|
|
1759
|
+
if (issue.project) {
|
|
1760
|
+
projects.set(issue.project.name, (projects.get(issue.project.name) ?? 0) + 1);
|
|
1761
|
+
}
|
|
1762
|
+
const actor = {
|
|
1763
|
+
id: assigneeId,
|
|
1764
|
+
kind: "human",
|
|
1765
|
+
name: issue.assignee?.name ?? "unassigned"
|
|
1766
|
+
};
|
|
1767
|
+
if (created >= since) {
|
|
1768
|
+
issuesCreated++;
|
|
1769
|
+
events.push({
|
|
1770
|
+
id: `linear-created-${issue.id}`,
|
|
1771
|
+
timestamp: issue.createdAt,
|
|
1772
|
+
actor: {
|
|
1773
|
+
id: issue.creator?.id ?? "unknown",
|
|
1774
|
+
kind: "human",
|
|
1775
|
+
name: issue.creator?.name ?? "unknown"
|
|
1776
|
+
},
|
|
1777
|
+
kind: "issue_created",
|
|
1778
|
+
content: `[${issue.identifier}] ${issue.title}`,
|
|
1779
|
+
metadata: {
|
|
1780
|
+
issueId: issue.id,
|
|
1781
|
+
url: issue.url,
|
|
1782
|
+
team: issue.team?.name,
|
|
1783
|
+
project: issue.project?.name,
|
|
1784
|
+
state: issue.state?.name
|
|
1785
|
+
}
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
if (completed && completed >= since) {
|
|
1789
|
+
issuesCompleted++;
|
|
1790
|
+
events.push({
|
|
1791
|
+
id: `linear-completed-${issue.id}`,
|
|
1792
|
+
timestamp: issue.completedAt,
|
|
1793
|
+
actor,
|
|
1794
|
+
kind: "issue_completed",
|
|
1795
|
+
content: `[${issue.identifier}] ${issue.title}`,
|
|
1796
|
+
metadata: {
|
|
1797
|
+
issueId: issue.id,
|
|
1798
|
+
url: issue.url,
|
|
1799
|
+
team: issue.team?.name,
|
|
1800
|
+
project: issue.project?.name,
|
|
1801
|
+
cycleDays: issue.cycle?.startsAt && issue.completedAt ? Math.round(
|
|
1802
|
+
(new Date(issue.completedAt).getTime() - new Date(issue.cycle.startsAt).getTime()) / (24 * 60 * 60 * 1e3)
|
|
1803
|
+
) : null
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
if (!completed && !issue.canceledAt) {
|
|
1808
|
+
issuesOpen++;
|
|
1809
|
+
const isInProgress = issue.state?.type === "started";
|
|
1810
|
+
const idleMs = now - updated.getTime();
|
|
1811
|
+
if (isInProgress && idleMs > stallThresholdMs) issuesStalled++;
|
|
1812
|
+
}
|
|
1813
|
+
for (const comment of issue.comments?.nodes ?? []) {
|
|
1814
|
+
const commentedAt = new Date(comment.createdAt);
|
|
1815
|
+
if (commentedAt < since) continue;
|
|
1816
|
+
commentsTotal++;
|
|
1817
|
+
events.push({
|
|
1818
|
+
id: `linear-comment-${comment.id}`,
|
|
1819
|
+
timestamp: comment.createdAt,
|
|
1820
|
+
actor: {
|
|
1821
|
+
id: comment.user?.id ?? "unknown",
|
|
1822
|
+
kind: "human",
|
|
1823
|
+
name: comment.user?.name ?? "unknown"
|
|
1824
|
+
},
|
|
1825
|
+
kind: "issue_comment",
|
|
1826
|
+
content: comment.body.slice(0, 280),
|
|
1827
|
+
metadata: {
|
|
1828
|
+
issueId: issue.id,
|
|
1829
|
+
issueIdentifier: issue.identifier,
|
|
1830
|
+
url: issue.url
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
let cycleCompletionRate = null;
|
|
1836
|
+
if (rawCycles.length > 0) {
|
|
1837
|
+
const rates = [];
|
|
1838
|
+
for (const cycle of rawCycles) {
|
|
1839
|
+
const committed = cycle.issueCountHistory?.at(0) ?? 0;
|
|
1840
|
+
const completed = cycle.completedIssueCountHistory?.at(-1) ?? 0;
|
|
1841
|
+
if (committed > 0) rates.push(completed / committed);
|
|
1842
|
+
}
|
|
1843
|
+
if (rates.length > 0) {
|
|
1844
|
+
cycleCompletionRate = Math.round(rates.reduce((a, b) => a + b, 0) / rates.length * 100) / 100;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
const topProjects = [...projects.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([name]) => name);
|
|
1848
|
+
const signals = {
|
|
1849
|
+
issuesCreated,
|
|
1850
|
+
issuesCompleted,
|
|
1851
|
+
issuesOpen,
|
|
1852
|
+
issuesStalled,
|
|
1853
|
+
cycleCompletionRate,
|
|
1854
|
+
uniqueAssignees: assignees.size,
|
|
1855
|
+
commentsTotal,
|
|
1856
|
+
topProjects
|
|
1857
|
+
};
|
|
1858
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
1859
|
+
return { events, signals };
|
|
1860
|
+
}
|
|
1861
|
+
function formatLinearSignalsForPrompt(signals) {
|
|
1862
|
+
if (signals.issuesCreated === 0 && signals.issuesCompleted === 0 && signals.issuesOpen === 0) {
|
|
1863
|
+
return "";
|
|
1864
|
+
}
|
|
1865
|
+
const lines = [
|
|
1866
|
+
"## Linear Activity (planned work vs. shipped outcome)",
|
|
1867
|
+
"",
|
|
1868
|
+
`${signals.issuesCreated} issues created, ${signals.issuesCompleted} completed in window.`,
|
|
1869
|
+
`${signals.issuesOpen} issues still open.`
|
|
1870
|
+
];
|
|
1871
|
+
if (signals.issuesStalled > 0) {
|
|
1872
|
+
lines.push(
|
|
1873
|
+
`${signals.issuesStalled} in-progress issues haven't moved in 14+ days (stalled).`
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
if (signals.cycleCompletionRate !== null) {
|
|
1877
|
+
const pct = Math.round(signals.cycleCompletionRate * 100);
|
|
1878
|
+
lines.push(`Cycles ended in window completed ${pct}% of what was committed.`);
|
|
1879
|
+
}
|
|
1880
|
+
if (signals.uniqueAssignees > 0) {
|
|
1881
|
+
lines.push(`${signals.uniqueAssignees} unique assignees active.`);
|
|
1882
|
+
}
|
|
1883
|
+
if (signals.commentsTotal > 0) {
|
|
1884
|
+
lines.push(`${signals.commentsTotal} comments across issues in window.`);
|
|
1885
|
+
}
|
|
1886
|
+
if (signals.topProjects.length > 0) {
|
|
1887
|
+
lines.push(`Most active projects: ${signals.topProjects.join(", ")}.`);
|
|
1888
|
+
}
|
|
1889
|
+
lines.push("");
|
|
1890
|
+
lines.push("Linear is where the team states what it will build.");
|
|
1891
|
+
lines.push("GitHub is where the team reveals what actually got built.");
|
|
1892
|
+
lines.push("Low completion rate + high creation rate = planning faster than shipping.");
|
|
1893
|
+
lines.push("High stalled count = commitments made but not honored.");
|
|
1894
|
+
lines.push("Compare Linear signals against GitHub to find the stated-vs-shipped gap.");
|
|
1895
|
+
return lines.join("\n");
|
|
1896
|
+
}
|
|
1897
|
+
async function fetchLinearGraphQL(apiKey, query, variables) {
|
|
1898
|
+
const res = await fetch("https://api.linear.app/graphql", {
|
|
1899
|
+
method: "POST",
|
|
1900
|
+
headers: {
|
|
1901
|
+
// Linear accepts the raw API key in Authorization with no "Bearer" prefix.
|
|
1902
|
+
Authorization: apiKey,
|
|
1903
|
+
"Content-Type": "application/json"
|
|
1904
|
+
},
|
|
1905
|
+
body: JSON.stringify({ query, variables })
|
|
1906
|
+
});
|
|
1907
|
+
if (!res.ok) {
|
|
1908
|
+
throw new Error(
|
|
1909
|
+
`Linear API error ${res.status}: ${(await res.text()).slice(0, 300)}`
|
|
1910
|
+
);
|
|
1911
|
+
}
|
|
1912
|
+
const json = await res.json();
|
|
1913
|
+
if (json.errors && json.errors.length > 0) {
|
|
1914
|
+
throw new Error(
|
|
1915
|
+
`Linear GraphQL errors: ${json.errors.map((e) => e.message).join("; ")}`
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
if (!json.data) {
|
|
1919
|
+
throw new Error("Linear API returned no data");
|
|
1920
|
+
}
|
|
1921
|
+
return json.data;
|
|
1922
|
+
}
|
|
1923
|
+
var init_linear = __esm({
|
|
1924
|
+
"src/radiant/adapters/linear.ts"() {
|
|
1925
|
+
"use strict";
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
|
|
1929
|
+
// src/radiant/core/git-remote.ts
|
|
1930
|
+
function resolveGitConfigPath(repoDir) {
|
|
1931
|
+
const dotGit = (0, import_path.join)(repoDir, ".git");
|
|
1932
|
+
if (!(0, import_fs.existsSync)(dotGit)) return null;
|
|
1933
|
+
try {
|
|
1934
|
+
const stat = (0, import_fs.statSync)(dotGit);
|
|
1935
|
+
if (stat.isDirectory()) {
|
|
1936
|
+
return (0, import_path.join)(dotGit, "config");
|
|
1937
|
+
}
|
|
1938
|
+
if (stat.isFile()) {
|
|
1939
|
+
const content = (0, import_fs.readFileSync)(dotGit, "utf-8");
|
|
1940
|
+
const match = /^gitdir:\s*(.+)$/m.exec(content);
|
|
1941
|
+
if (!match) return null;
|
|
1942
|
+
const gitDir = (0, import_path.resolve)(repoDir, match[1].trim());
|
|
1943
|
+
const configPath = (0, import_path.join)(gitDir, "config");
|
|
1944
|
+
return (0, import_fs.existsSync)(configPath) ? configPath : null;
|
|
1945
|
+
}
|
|
1946
|
+
} catch {
|
|
1947
|
+
return null;
|
|
1948
|
+
}
|
|
1949
|
+
return null;
|
|
1950
|
+
}
|
|
1951
|
+
function readOriginRemote(repoDir) {
|
|
1952
|
+
const configPath = resolveGitConfigPath(repoDir);
|
|
1953
|
+
if (!configPath) return null;
|
|
1954
|
+
try {
|
|
1955
|
+
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
1956
|
+
const sectionRe = /\[remote "origin"\]\s*\n((?:(?!\[)[^\n]*\n?)*)/;
|
|
1957
|
+
const section = sectionRe.exec(raw);
|
|
1958
|
+
if (!section) return null;
|
|
1959
|
+
const urlRe = /^\s*url\s*=\s*(.+?)\s*$/m;
|
|
1960
|
+
const url = urlRe.exec(section[1]);
|
|
1961
|
+
return url ? url[1] : null;
|
|
1962
|
+
} catch {
|
|
1963
|
+
return null;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
function parseRemoteUrl(url) {
|
|
1967
|
+
const trimmed = url.trim();
|
|
1968
|
+
if (!trimmed) return null;
|
|
1969
|
+
const ssh = /^git@([^:]+):([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
1970
|
+
if (ssh) return { host: ssh[1], owner: ssh[2], repo: ssh[3] };
|
|
1971
|
+
const sshProto = /^ssh:\/\/git@([^/]+)\/([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
1972
|
+
if (sshProto) return { host: sshProto[1], owner: sshProto[2], repo: sshProto[3] };
|
|
1973
|
+
const https = /^https?:\/\/(?:[^@/]+@)?([^/]+)\/([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
1974
|
+
if (https) return { host: https[1], owner: https[2], repo: https[3] };
|
|
1975
|
+
return null;
|
|
1976
|
+
}
|
|
1977
|
+
function getRepoOrigin(repoDir) {
|
|
1978
|
+
const url = readOriginRemote(repoDir);
|
|
1979
|
+
if (!url) return null;
|
|
1980
|
+
return parseRemoteUrl(url);
|
|
1981
|
+
}
|
|
1982
|
+
var import_fs, import_path;
|
|
1983
|
+
var init_git_remote = __esm({
|
|
1984
|
+
"src/radiant/core/git-remote.ts"() {
|
|
1985
|
+
"use strict";
|
|
1986
|
+
import_fs = require("fs");
|
|
1987
|
+
import_path = require("path");
|
|
1988
|
+
}
|
|
1989
|
+
});
|
|
1990
|
+
|
|
1991
|
+
// src/radiant/core/extends.ts
|
|
1992
|
+
function loadExtendsConfig(repoDir) {
|
|
1993
|
+
const configPath = (0, import_path2.join)(repoDir, ".neuroverse", "config.json");
|
|
1994
|
+
if (!(0, import_fs2.existsSync)(configPath)) return null;
|
|
1995
|
+
try {
|
|
1996
|
+
const raw = (0, import_fs2.readFileSync)(configPath, "utf-8");
|
|
1997
|
+
const parsed = JSON.parse(raw);
|
|
1998
|
+
return parsed;
|
|
1999
|
+
} catch {
|
|
2000
|
+
return null;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
function parseExtendsSpec(raw) {
|
|
2004
|
+
const trimmed = raw.trim();
|
|
2005
|
+
if (!trimmed) return null;
|
|
2006
|
+
if (trimmed.startsWith("github:")) {
|
|
2007
|
+
const rest = trimmed.slice("github:".length);
|
|
2008
|
+
const match = /^([^/]+)\/([^@:]+)(?:@([^:]+))?(?::(.+))?$/.exec(rest);
|
|
2009
|
+
if (!match) return null;
|
|
2010
|
+
return {
|
|
2011
|
+
raw: trimmed,
|
|
2012
|
+
kind: "github",
|
|
2013
|
+
owner: match[1],
|
|
2014
|
+
repo: match[2],
|
|
2015
|
+
ref: match[3] ?? "HEAD",
|
|
2016
|
+
subpath: match[4] ?? ""
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("../") || (0, import_path2.isAbsolute)(trimmed)) {
|
|
2020
|
+
return { raw: trimmed, kind: "local", path: trimmed };
|
|
2021
|
+
}
|
|
2022
|
+
return null;
|
|
2023
|
+
}
|
|
2024
|
+
function getCacheDir(spec, baseCacheDir) {
|
|
2025
|
+
const root = baseCacheDir ?? (0, import_path2.join)((0, import_os.homedir)(), ".neuroverse", "cache", "extends");
|
|
2026
|
+
const key = (0, import_crypto.createHash)("sha256").update(spec.raw).digest("hex").slice(0, 16);
|
|
2027
|
+
return (0, import_path2.join)(root, key);
|
|
2028
|
+
}
|
|
2029
|
+
function isCacheFresh(cacheDir, ttlMs) {
|
|
2030
|
+
const stampPath = (0, import_path2.join)(cacheDir, ".neuroverse-fetched");
|
|
2031
|
+
if (!(0, import_fs2.existsSync)(stampPath)) return false;
|
|
2032
|
+
try {
|
|
2033
|
+
const stamp = (0, import_fs2.statSync)(stampPath);
|
|
2034
|
+
return Date.now() - stamp.mtimeMs < ttlMs;
|
|
2035
|
+
} catch {
|
|
2036
|
+
return false;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
function markCacheFresh(cacheDir) {
|
|
2040
|
+
const stampPath = (0, import_path2.join)(cacheDir, ".neuroverse-fetched");
|
|
2041
|
+
try {
|
|
2042
|
+
(0, import_fs2.mkdirSync)(cacheDir, { recursive: true });
|
|
2043
|
+
(0, import_fs2.writeFileSync)(stampPath, (/* @__PURE__ */ new Date()).toISOString());
|
|
2044
|
+
} catch {
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
function resolveExtendsSpec(spec, repoDir, options) {
|
|
2048
|
+
if (spec.kind === "local") {
|
|
2049
|
+
const full = (0, import_path2.isAbsolute)(spec.path) ? spec.path : (0, import_path2.resolve)(repoDir, spec.path);
|
|
2050
|
+
if (!(0, import_fs2.existsSync)(full)) {
|
|
2051
|
+
return { spec, dir: null, warning: `local extends path not found: ${full}` };
|
|
2052
|
+
}
|
|
2053
|
+
return { spec, dir: full };
|
|
2054
|
+
}
|
|
2055
|
+
const cacheRoot = options?.cacheDir;
|
|
2056
|
+
const ttl = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
2057
|
+
const cacheDir = getCacheDir(spec, cacheRoot);
|
|
2058
|
+
const fresh = isCacheFresh(cacheDir, ttl);
|
|
2059
|
+
const needsFetch = options?.forceRefresh || !fresh || !(0, import_fs2.existsSync)(cacheDir);
|
|
2060
|
+
if (needsFetch && options?.noFetch) {
|
|
2061
|
+
if ((0, import_fs2.existsSync)(cacheDir) && (0, import_fs2.existsSync)((0, import_path2.join)(cacheDir, ".neuroverse-fetched"))) {
|
|
2062
|
+
return resolveSubpath(spec, cacheDir);
|
|
2063
|
+
}
|
|
2064
|
+
return options?.silentOnMissing ? { spec, dir: null } : { spec, dir: null, warning: `NEUROVERSE_NO_FETCH set and no cache for ${spec.raw}` };
|
|
2065
|
+
}
|
|
2066
|
+
if (needsFetch) {
|
|
2067
|
+
const fetcher = options?.fetcher ?? defaultGitFetcher;
|
|
2068
|
+
try {
|
|
2069
|
+
fetcher(spec, cacheDir);
|
|
2070
|
+
markCacheFresh(cacheDir);
|
|
2071
|
+
} catch (err) {
|
|
2072
|
+
if ((0, import_fs2.existsSync)(cacheDir) && (0, import_fs2.existsSync)((0, import_path2.join)(cacheDir, ".neuroverse-fetched"))) {
|
|
2073
|
+
const result = resolveSubpath(spec, cacheDir);
|
|
2074
|
+
return options?.silentOnMissing ? result : { ...result, warning: `fetch failed for ${spec.raw}, using stale cache: ${err.message}` };
|
|
2075
|
+
}
|
|
2076
|
+
return options?.silentOnMissing ? { spec, dir: null } : { spec, dir: null, warning: `fetch failed for ${spec.raw}: ${err.message}` };
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
return resolveSubpath(spec, cacheDir);
|
|
2080
|
+
}
|
|
2081
|
+
function resolveSubpath(spec, cacheDir) {
|
|
2082
|
+
const target = spec.subpath ? (0, import_path2.join)(cacheDir, spec.subpath) : cacheDir;
|
|
2083
|
+
if (!(0, import_fs2.existsSync)(target)) {
|
|
2084
|
+
return { spec, dir: null, warning: `subpath not found in ${spec.raw}: ${spec.subpath}` };
|
|
2085
|
+
}
|
|
2086
|
+
if (!spec.subpath) {
|
|
2087
|
+
const candidates = [
|
|
2088
|
+
(0, import_path2.join)(target, "worlds"),
|
|
2089
|
+
(0, import_path2.join)(target, ".neuroverse", "worlds")
|
|
2090
|
+
];
|
|
2091
|
+
for (const c of candidates) {
|
|
2092
|
+
if ((0, import_fs2.existsSync)(c)) return { spec, dir: c };
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
return { spec, dir: target };
|
|
2096
|
+
}
|
|
2097
|
+
function detectOrgExtendsSpec(repoDir) {
|
|
2098
|
+
const origin = getRepoOrigin(repoDir);
|
|
2099
|
+
if (!origin) return null;
|
|
2100
|
+
if (origin.host !== "github.com") return null;
|
|
2101
|
+
if (origin.repo === "worlds") return null;
|
|
2102
|
+
return {
|
|
2103
|
+
raw: `github:${origin.owner}/worlds`,
|
|
2104
|
+
kind: "github",
|
|
2105
|
+
owner: origin.owner,
|
|
2106
|
+
repo: "worlds",
|
|
2107
|
+
ref: "HEAD",
|
|
2108
|
+
subpath: ""
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
function resolveAllExtends(repoDir, options) {
|
|
2112
|
+
const config = options?.config !== void 0 ? options.config : loadExtendsConfig(repoDir);
|
|
2113
|
+
if (!config?.extends || config.extends.length === 0) return [];
|
|
2114
|
+
const results = [];
|
|
2115
|
+
for (const raw of config.extends) {
|
|
2116
|
+
const spec = parseExtendsSpec(raw);
|
|
2117
|
+
if (!spec) {
|
|
2118
|
+
results.push({
|
|
2119
|
+
spec: { raw, kind: "local" },
|
|
2120
|
+
dir: null,
|
|
2121
|
+
warning: `unparseable extends spec: ${raw}`
|
|
2122
|
+
});
|
|
2123
|
+
continue;
|
|
2124
|
+
}
|
|
2125
|
+
results.push(resolveExtendsSpec(spec, repoDir, options));
|
|
2126
|
+
}
|
|
2127
|
+
return results;
|
|
2128
|
+
}
|
|
2129
|
+
var import_fs2, import_path2, import_os, import_crypto, import_child_process, DEFAULT_TTL_MS, defaultGitFetcher;
|
|
2130
|
+
var init_extends = __esm({
|
|
2131
|
+
"src/radiant/core/extends.ts"() {
|
|
2132
|
+
"use strict";
|
|
2133
|
+
import_fs2 = require("fs");
|
|
2134
|
+
import_path2 = require("path");
|
|
2135
|
+
import_os = require("os");
|
|
2136
|
+
import_crypto = require("crypto");
|
|
2137
|
+
import_child_process = require("child_process");
|
|
2138
|
+
init_git_remote();
|
|
2139
|
+
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
2140
|
+
defaultGitFetcher = (spec, destDir) => {
|
|
2141
|
+
if (spec.kind !== "github") return;
|
|
2142
|
+
const url = `https://github.com/${spec.owner}/${spec.repo}.git`;
|
|
2143
|
+
const parent = (0, import_path2.resolve)(destDir, "..");
|
|
2144
|
+
(0, import_fs2.mkdirSync)(parent, { recursive: true });
|
|
2145
|
+
if ((0, import_fs2.existsSync)(destDir)) {
|
|
2146
|
+
(0, import_fs2.rmSync)(destDir, { recursive: true, force: true });
|
|
2147
|
+
}
|
|
2148
|
+
const args = ["clone", "--depth", "1", "--filter=blob:none"];
|
|
2149
|
+
if (spec.ref && spec.ref !== "HEAD") {
|
|
2150
|
+
args.push("--branch", spec.ref);
|
|
2151
|
+
}
|
|
2152
|
+
args.push(url, destDir);
|
|
2153
|
+
(0, import_child_process.execFileSync)("git", args, { stdio: "pipe" });
|
|
2154
|
+
};
|
|
2155
|
+
}
|
|
2156
|
+
});
|
|
2157
|
+
|
|
1673
2158
|
// src/radiant/core/discovery.ts
|
|
1674
2159
|
function discoverWorlds(options) {
|
|
1675
2160
|
const worlds = [];
|
|
1676
|
-
const
|
|
1677
|
-
|
|
2161
|
+
const warnings = [];
|
|
2162
|
+
const forceRefresh = process.env.NEUROVERSE_REFRESH === "1";
|
|
2163
|
+
const noFetch = process.env.NEUROVERSE_NO_FETCH === "1";
|
|
2164
|
+
const noOrg = options?.disableOrg || process.env.NEUROVERSE_NO_ORG === "1";
|
|
2165
|
+
const userDir = options?.userWorldsDir ?? (0, import_path3.join)((0, import_os2.homedir)(), ".neuroverse", "worlds");
|
|
2166
|
+
if ((0, import_fs3.existsSync)(userDir)) {
|
|
1678
2167
|
worlds.push(...loadWorldsFromDir(userDir, "user"));
|
|
1679
2168
|
}
|
|
2169
|
+
if (!noOrg && !options?.explicitWorldsDir) {
|
|
2170
|
+
const specs = [];
|
|
2171
|
+
if (options?.repoDir) {
|
|
2172
|
+
const fromGit = detectOrgExtendsSpec(options.repoDir);
|
|
2173
|
+
if (fromGit) specs.push(fromGit);
|
|
2174
|
+
}
|
|
2175
|
+
if (options?.scopeOwner) {
|
|
2176
|
+
const already = specs.some(
|
|
2177
|
+
(s) => s.owner?.toLowerCase() === options.scopeOwner.toLowerCase()
|
|
2178
|
+
);
|
|
2179
|
+
if (!already) {
|
|
2180
|
+
specs.push({
|
|
2181
|
+
raw: `github:${options.scopeOwner}/worlds`,
|
|
2182
|
+
kind: "github",
|
|
2183
|
+
owner: options.scopeOwner,
|
|
2184
|
+
repo: "worlds"
|
|
2185
|
+
});
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
const baseDir = options?.repoDir ?? process.cwd();
|
|
2189
|
+
for (const spec of specs) {
|
|
2190
|
+
const result = resolveExtendsSpec(spec, baseDir, {
|
|
2191
|
+
cacheDir: options?.extendsCacheDir,
|
|
2192
|
+
fetcher: options?.extendsFetcher,
|
|
2193
|
+
ttlMs: options?.extendsTtlMs,
|
|
2194
|
+
forceRefresh,
|
|
2195
|
+
noFetch,
|
|
2196
|
+
silentOnMissing: true
|
|
2197
|
+
});
|
|
2198
|
+
worlds.push(...loadExtendsWorlds(result, "org"));
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
if (options?.repoDir && !options.disableExtends && !options.explicitWorldsDir) {
|
|
2202
|
+
const results = resolveAllExtends(options.repoDir, {
|
|
2203
|
+
cacheDir: options.extendsCacheDir,
|
|
2204
|
+
fetcher: options.extendsFetcher,
|
|
2205
|
+
ttlMs: options.extendsTtlMs,
|
|
2206
|
+
forceRefresh,
|
|
2207
|
+
noFetch
|
|
2208
|
+
});
|
|
2209
|
+
for (const result of results) {
|
|
2210
|
+
worlds.push(...loadExtendsWorlds(result, "extends"));
|
|
2211
|
+
if (result.warning) warnings.push(result.warning);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
1680
2214
|
if (options?.explicitWorldsDir) {
|
|
1681
2215
|
worlds.push(...loadWorldsFromDir(options.explicitWorldsDir, "repo"));
|
|
1682
2216
|
} else if (options?.repoDir) {
|
|
1683
2217
|
const repoPaths = [
|
|
1684
|
-
(0,
|
|
1685
|
-
(0,
|
|
2218
|
+
(0, import_path3.join)(options.repoDir, "worlds"),
|
|
2219
|
+
(0, import_path3.join)(options.repoDir, ".neuroverse", "worlds")
|
|
1686
2220
|
];
|
|
1687
2221
|
for (const p of repoPaths) {
|
|
1688
|
-
if ((0,
|
|
2222
|
+
if ((0, import_fs3.existsSync)(p)) {
|
|
1689
2223
|
worlds.push(...loadWorldsFromDir(p, "repo"));
|
|
1690
2224
|
break;
|
|
1691
2225
|
}
|
|
1692
2226
|
}
|
|
1693
2227
|
}
|
|
1694
|
-
const combinedContent = worlds.map((w) =>
|
|
1695
|
-
${w.
|
|
2228
|
+
const combinedContent = worlds.map((w) => {
|
|
2229
|
+
const tag = w.extendsFrom ? `<!-- world: ${w.name} (${w.source} ${w.extendsFrom}) -->` : `<!-- world: ${w.name} (${w.source}) -->`;
|
|
2230
|
+
return `${tag}
|
|
2231
|
+
${w.content}`;
|
|
2232
|
+
}).join("\n\n---\n\n");
|
|
1696
2233
|
const summary = worlds.length === 0 ? "no worlds discovered" : worlds.map((w) => `${w.name} (${w.source})`).join(", ");
|
|
1697
|
-
return { worlds, combinedContent, summary };
|
|
2234
|
+
return { worlds, combinedContent, summary, warnings };
|
|
2235
|
+
}
|
|
2236
|
+
function formatActiveWorlds(stack) {
|
|
2237
|
+
if (stack.worlds.length === 0) return "No worlds loaded.";
|
|
2238
|
+
const lines = ["ACTIVE WORLDS", ""];
|
|
2239
|
+
for (const w of stack.worlds) {
|
|
2240
|
+
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";
|
|
2241
|
+
lines.push(` ${w.name} (${sourceLabel})`);
|
|
2242
|
+
}
|
|
2243
|
+
if (stack.warnings.length > 0) {
|
|
2244
|
+
lines.push("", "WARNINGS");
|
|
2245
|
+
for (const w of stack.warnings) lines.push(` ${w}`);
|
|
2246
|
+
}
|
|
2247
|
+
return lines.join("\n");
|
|
2248
|
+
}
|
|
2249
|
+
function loadExtendsWorlds(result, source) {
|
|
2250
|
+
if (!result.dir) return [];
|
|
2251
|
+
const loaded = loadWorldsFromDir(result.dir, source);
|
|
2252
|
+
return loaded.map((w) => ({ ...w, extendsFrom: result.spec.raw }));
|
|
1698
2253
|
}
|
|
1699
2254
|
function loadWorldsFromDir(dirPath, source) {
|
|
1700
|
-
const dir = (0,
|
|
1701
|
-
if (!(0,
|
|
1702
|
-
const stat = (0,
|
|
2255
|
+
const dir = (0, import_path3.resolve)(dirPath);
|
|
2256
|
+
if (!(0, import_fs3.existsSync)(dir)) return [];
|
|
2257
|
+
const stat = (0, import_fs3.statSync)(dir);
|
|
1703
2258
|
if (stat.isFile() && dir.endsWith(".md")) {
|
|
1704
2259
|
try {
|
|
1705
2260
|
return [{
|
|
1706
|
-
name: (0,
|
|
2261
|
+
name: (0, import_path3.basename)(dir).replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
1707
2262
|
source,
|
|
1708
2263
|
path: dir,
|
|
1709
|
-
content: (0,
|
|
2264
|
+
content: (0, import_fs3.readFileSync)(dir, "utf-8")
|
|
1710
2265
|
}];
|
|
1711
2266
|
} catch {
|
|
1712
2267
|
return [];
|
|
1713
2268
|
}
|
|
1714
2269
|
}
|
|
1715
2270
|
if (!stat.isDirectory()) return [];
|
|
1716
|
-
const files = (0,
|
|
2271
|
+
const files = (0, import_fs3.readdirSync)(dir).filter(
|
|
1717
2272
|
(f) => f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md")
|
|
1718
2273
|
).sort();
|
|
1719
2274
|
return files.map((f) => {
|
|
1720
|
-
const fullPath = (0,
|
|
2275
|
+
const fullPath = (0, import_path3.join)(dir, f);
|
|
1721
2276
|
return {
|
|
1722
2277
|
name: f.replace(/\.worldmodel\.md$/, "").replace(/\.nv-world\.md$/, ""),
|
|
1723
2278
|
source,
|
|
1724
2279
|
path: fullPath,
|
|
1725
|
-
content: (0,
|
|
2280
|
+
content: (0, import_fs3.readFileSync)(fullPath, "utf-8")
|
|
1726
2281
|
};
|
|
1727
2282
|
});
|
|
1728
2283
|
}
|
|
1729
|
-
var
|
|
2284
|
+
var import_fs3, import_path3, import_os2;
|
|
1730
2285
|
var init_discovery = __esm({
|
|
1731
2286
|
"src/radiant/core/discovery.ts"() {
|
|
1732
2287
|
"use strict";
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
2288
|
+
import_fs3 = require("fs");
|
|
2289
|
+
import_path3 = require("path");
|
|
2290
|
+
import_os2 = require("os");
|
|
2291
|
+
init_extends();
|
|
1736
2292
|
}
|
|
1737
2293
|
});
|
|
1738
2294
|
|
|
1739
2295
|
// src/radiant/adapters/exocortex.ts
|
|
1740
2296
|
function readExocortex(dirPath, repoName) {
|
|
1741
|
-
const dir = (0,
|
|
2297
|
+
const dir = (0, import_path4.resolve)(dirPath);
|
|
1742
2298
|
let filesLoaded = 0;
|
|
1743
2299
|
function tryRead(...paths) {
|
|
1744
2300
|
for (const p of paths) {
|
|
1745
|
-
const full = (0,
|
|
1746
|
-
if ((0,
|
|
2301
|
+
const full = (0, import_path4.join)(dir, p);
|
|
2302
|
+
if ((0, import_fs4.existsSync)(full)) {
|
|
1747
2303
|
try {
|
|
1748
|
-
const content = (0,
|
|
2304
|
+
const content = (0, import_fs4.readFileSync)(full, "utf-8").trim();
|
|
1749
2305
|
if (content) {
|
|
1750
2306
|
filesLoaded++;
|
|
1751
2307
|
return content;
|
|
@@ -1827,33 +2383,33 @@ function summarizeExocortex(ctx) {
|
|
|
1827
2383
|
if (ctx.methods) loaded.push("methods");
|
|
1828
2384
|
return `${loaded.join(", ")} (${ctx.filesLoaded} files)`;
|
|
1829
2385
|
}
|
|
1830
|
-
var
|
|
2386
|
+
var import_fs4, import_path4;
|
|
1831
2387
|
var init_exocortex = __esm({
|
|
1832
2388
|
"src/radiant/adapters/exocortex.ts"() {
|
|
1833
2389
|
"use strict";
|
|
1834
|
-
|
|
1835
|
-
|
|
2390
|
+
import_fs4 = require("fs");
|
|
2391
|
+
import_path4 = require("path");
|
|
1836
2392
|
}
|
|
1837
2393
|
});
|
|
1838
2394
|
|
|
1839
2395
|
// src/radiant/memory/palace.ts
|
|
1840
2396
|
function writeRead(exocortexDir, frontmatter, text) {
|
|
1841
|
-
const dir = (0,
|
|
1842
|
-
(0,
|
|
2397
|
+
const dir = (0, import_path5.resolve)(exocortexDir, "radiant", "reads");
|
|
2398
|
+
(0, import_fs5.mkdirSync)(dir, { recursive: true });
|
|
1843
2399
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1844
2400
|
const filename = `${date}.md`;
|
|
1845
|
-
const filepath = (0,
|
|
2401
|
+
const filepath = (0, import_path5.join)(dir, filename);
|
|
1846
2402
|
const content = `${frontmatter}
|
|
1847
2403
|
|
|
1848
2404
|
${text}
|
|
1849
2405
|
`;
|
|
1850
|
-
(0,
|
|
2406
|
+
(0, import_fs5.writeFileSync)(filepath, content, "utf-8");
|
|
1851
2407
|
return filepath;
|
|
1852
2408
|
}
|
|
1853
2409
|
function updateKnowledge(exocortexDir, persistence, options) {
|
|
1854
|
-
const dir = (0,
|
|
1855
|
-
(0,
|
|
1856
|
-
const filepath = (0,
|
|
2410
|
+
const dir = (0, import_path5.resolve)(exocortexDir, "radiant");
|
|
2411
|
+
(0, import_fs5.mkdirSync)(dir, { recursive: true });
|
|
2412
|
+
const filepath = (0, import_path5.join)(dir, "knowledge.md");
|
|
1857
2413
|
const totalReads = options?.totalReads ?? 0;
|
|
1858
2414
|
const existingUntriggered = loadUntriggeredCounts(filepath);
|
|
1859
2415
|
const lines = [
|
|
@@ -1940,14 +2496,14 @@ function updateKnowledge(exocortexDir, persistence, options) {
|
|
|
1940
2496
|
lines.push(`${name}=${count}`);
|
|
1941
2497
|
}
|
|
1942
2498
|
lines.push("-->");
|
|
1943
|
-
(0,
|
|
2499
|
+
(0, import_fs5.writeFileSync)(filepath, lines.join("\n"), "utf-8");
|
|
1944
2500
|
return filepath;
|
|
1945
2501
|
}
|
|
1946
2502
|
function loadUntriggeredCounts(filepath) {
|
|
1947
2503
|
const counts = /* @__PURE__ */ new Map();
|
|
1948
|
-
if (!(0,
|
|
2504
|
+
if (!(0, import_fs5.existsSync)(filepath)) return counts;
|
|
1949
2505
|
try {
|
|
1950
|
-
const content = (0,
|
|
2506
|
+
const content = (0, import_fs5.readFileSync)(filepath, "utf-8");
|
|
1951
2507
|
const match = content.match(
|
|
1952
2508
|
/<!-- untriggered_counts[\s\S]*?-->/
|
|
1953
2509
|
);
|
|
@@ -1965,13 +2521,13 @@ function loadUntriggeredCounts(filepath) {
|
|
|
1965
2521
|
return counts;
|
|
1966
2522
|
}
|
|
1967
2523
|
function loadPriorReads(exocortexDir) {
|
|
1968
|
-
const dir = (0,
|
|
1969
|
-
if (!(0,
|
|
1970
|
-
const files = (0,
|
|
2524
|
+
const dir = (0, import_path5.resolve)(exocortexDir, "radiant", "reads");
|
|
2525
|
+
if (!(0, import_fs5.existsSync)(dir)) return [];
|
|
2526
|
+
const files = (0, import_fs5.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
1971
2527
|
const reads = [];
|
|
1972
2528
|
for (const filename of files) {
|
|
1973
|
-
const filepath = (0,
|
|
1974
|
-
const content = (0,
|
|
2529
|
+
const filepath = (0, import_path5.join)(dir, filename);
|
|
2530
|
+
const content = (0, import_fs5.readFileSync)(filepath, "utf-8");
|
|
1975
2531
|
const date = filename.replace(".md", "");
|
|
1976
2532
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1977
2533
|
const frontmatter = fmMatch ? fmMatch[1] : "";
|
|
@@ -2005,12 +2561,12 @@ function computePersistence(priorReads, currentPatternNames) {
|
|
|
2005
2561
|
dates: dates.sort()
|
|
2006
2562
|
})).sort((a, b) => b.occurrences - a.occurrences);
|
|
2007
2563
|
}
|
|
2008
|
-
var
|
|
2564
|
+
var import_fs5, import_path5;
|
|
2009
2565
|
var init_palace = __esm({
|
|
2010
2566
|
"src/radiant/memory/palace.ts"() {
|
|
2011
2567
|
"use strict";
|
|
2012
|
-
|
|
2013
|
-
|
|
2568
|
+
import_fs5 = require("fs");
|
|
2569
|
+
import_path5 = require("path");
|
|
2014
2570
|
}
|
|
2015
2571
|
});
|
|
2016
2572
|
|
|
@@ -3119,10 +3675,10 @@ var init_guard_engine = __esm({
|
|
|
3119
3675
|
// src/loader/world-loader.ts
|
|
3120
3676
|
async function loadWorldFromDirectory(dirPath) {
|
|
3121
3677
|
const { readFile } = await import("fs/promises");
|
|
3122
|
-
const { join:
|
|
3678
|
+
const { join: join8 } = await import("path");
|
|
3123
3679
|
const { readdirSync: readdirSync6 } = await import("fs");
|
|
3124
3680
|
async function readJson(filename) {
|
|
3125
|
-
const filePath =
|
|
3681
|
+
const filePath = join8(dirPath, filename);
|
|
3126
3682
|
try {
|
|
3127
3683
|
const content = await readFile(filePath, "utf-8");
|
|
3128
3684
|
return JSON.parse(content);
|
|
@@ -3152,11 +3708,11 @@ async function loadWorldFromDirectory(dirPath) {
|
|
|
3152
3708
|
const metadataJson = await readJson("metadata.json");
|
|
3153
3709
|
const rules = [];
|
|
3154
3710
|
try {
|
|
3155
|
-
const rulesDir =
|
|
3711
|
+
const rulesDir = join8(dirPath, "rules");
|
|
3156
3712
|
const ruleFiles = readdirSync6(rulesDir).filter((f) => f.endsWith(".json")).sort();
|
|
3157
3713
|
for (const file of ruleFiles) {
|
|
3158
3714
|
try {
|
|
3159
|
-
const content = await readFile(
|
|
3715
|
+
const content = await readFile(join8(rulesDir, file), "utf-8");
|
|
3160
3716
|
rules.push(JSON.parse(content));
|
|
3161
3717
|
} catch (err) {
|
|
3162
3718
|
process.stderr.write(
|
|
@@ -3499,6 +4055,144 @@ var init_signals = __esm({
|
|
|
3499
4055
|
}
|
|
3500
4056
|
});
|
|
3501
4057
|
|
|
4058
|
+
// src/radiant/core/vocabulary.ts
|
|
4059
|
+
function extractDeclaredVocabulary(worldmodelContent) {
|
|
4060
|
+
const aligned = extractSection(worldmodelContent, "Aligned Behaviors").map(
|
|
4061
|
+
(b) => parseBehavior(b, "aligned")
|
|
4062
|
+
);
|
|
4063
|
+
const drift = extractSection(worldmodelContent, "Drift Behaviors").map(
|
|
4064
|
+
(b) => parseBehavior(b, "drift")
|
|
4065
|
+
);
|
|
4066
|
+
const allNames = [...aligned, ...drift].map((p) => p.name);
|
|
4067
|
+
return { aligned, drift, allNames };
|
|
4068
|
+
}
|
|
4069
|
+
function extractSection(content, header) {
|
|
4070
|
+
const escaped = header.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4071
|
+
const pattern = new RegExp(
|
|
4072
|
+
`##\\s+${escaped}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)`,
|
|
4073
|
+
"i"
|
|
4074
|
+
);
|
|
4075
|
+
const match = content.match(pattern);
|
|
4076
|
+
if (!match) return [];
|
|
4077
|
+
const body = match[1];
|
|
4078
|
+
const bullets = body.match(/^[-*]\s+.+$/gm);
|
|
4079
|
+
if (!bullets) return [];
|
|
4080
|
+
return bullets.map((b) => b.replace(/^[-*]\s+/, "").trim()).filter((b) => b.length > 0 && !b.startsWith("<!--"));
|
|
4081
|
+
}
|
|
4082
|
+
function parseBehavior(bullet, kind) {
|
|
4083
|
+
const explicit = bullet.match(
|
|
4084
|
+
/^`?([a-z][a-z0-9_]*)`?\s+[—\u2014-]\s+(.+)$/i
|
|
4085
|
+
);
|
|
4086
|
+
if (explicit && isSnakeCase(explicit[1])) {
|
|
4087
|
+
return {
|
|
4088
|
+
name: explicit[1].toLowerCase(),
|
|
4089
|
+
prose: explicit[2].trim(),
|
|
4090
|
+
kind
|
|
4091
|
+
};
|
|
4092
|
+
}
|
|
4093
|
+
return { name: snakeCaseName(bullet), prose: bullet, kind };
|
|
4094
|
+
}
|
|
4095
|
+
function isSnakeCase(s) {
|
|
4096
|
+
return /^[a-z][a-z0-9_]*$/.test(s);
|
|
4097
|
+
}
|
|
4098
|
+
function snakeCaseName(s) {
|
|
4099
|
+
const base = s.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
4100
|
+
if (base.length <= 60) return base;
|
|
4101
|
+
const truncated = base.slice(0, 60);
|
|
4102
|
+
const lastUnderscore = truncated.lastIndexOf("_");
|
|
4103
|
+
return lastUnderscore > 20 ? truncated.slice(0, lastUnderscore) : truncated;
|
|
4104
|
+
}
|
|
4105
|
+
function matchDeclaredPattern(candidateName, candidateDescription, vocabulary) {
|
|
4106
|
+
const candidateText = `${candidateName.replace(/_/g, " ")} ${candidateDescription}`;
|
|
4107
|
+
const candidateWords = contentWords(candidateText);
|
|
4108
|
+
if (candidateWords.size === 0) return null;
|
|
4109
|
+
let best = null;
|
|
4110
|
+
for (const pattern of [...vocabulary.aligned, ...vocabulary.drift]) {
|
|
4111
|
+
const proseWords = contentWords(pattern.prose);
|
|
4112
|
+
if (proseWords.size === 0) continue;
|
|
4113
|
+
let shared = 0;
|
|
4114
|
+
for (const w of proseWords) {
|
|
4115
|
+
if (candidateWords.has(w)) shared++;
|
|
4116
|
+
}
|
|
4117
|
+
const coverage = shared / proseWords.size;
|
|
4118
|
+
if (shared >= 2 && coverage >= 0.3) {
|
|
4119
|
+
if (!best || coverage > best.score) {
|
|
4120
|
+
best = { pattern, score: coverage };
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
return best?.pattern ?? null;
|
|
4125
|
+
}
|
|
4126
|
+
function contentWords(text) {
|
|
4127
|
+
const words = text.toLowerCase().match(/[a-z][a-z0-9_]+/g) ?? [];
|
|
4128
|
+
return new Set(words.filter((w) => w.length > 3 && !STOPWORDS.has(w)));
|
|
4129
|
+
}
|
|
4130
|
+
var STOPWORDS;
|
|
4131
|
+
var init_vocabulary = __esm({
|
|
4132
|
+
"src/radiant/core/vocabulary.ts"() {
|
|
4133
|
+
"use strict";
|
|
4134
|
+
STOPWORDS = /* @__PURE__ */ new Set([
|
|
4135
|
+
"about",
|
|
4136
|
+
"after",
|
|
4137
|
+
"against",
|
|
4138
|
+
"among",
|
|
4139
|
+
"around",
|
|
4140
|
+
"because",
|
|
4141
|
+
"been",
|
|
4142
|
+
"before",
|
|
4143
|
+
"being",
|
|
4144
|
+
"between",
|
|
4145
|
+
"both",
|
|
4146
|
+
"could",
|
|
4147
|
+
"does",
|
|
4148
|
+
"doing",
|
|
4149
|
+
"during",
|
|
4150
|
+
"each",
|
|
4151
|
+
"from",
|
|
4152
|
+
"further",
|
|
4153
|
+
"have",
|
|
4154
|
+
"having",
|
|
4155
|
+
"into",
|
|
4156
|
+
"itself",
|
|
4157
|
+
"most",
|
|
4158
|
+
"nor",
|
|
4159
|
+
"only",
|
|
4160
|
+
"other",
|
|
4161
|
+
"over",
|
|
4162
|
+
"same",
|
|
4163
|
+
"should",
|
|
4164
|
+
"some",
|
|
4165
|
+
"such",
|
|
4166
|
+
"than",
|
|
4167
|
+
"that",
|
|
4168
|
+
"their",
|
|
4169
|
+
"them",
|
|
4170
|
+
"then",
|
|
4171
|
+
"there",
|
|
4172
|
+
"these",
|
|
4173
|
+
"they",
|
|
4174
|
+
"this",
|
|
4175
|
+
"those",
|
|
4176
|
+
"through",
|
|
4177
|
+
"under",
|
|
4178
|
+
"until",
|
|
4179
|
+
"very",
|
|
4180
|
+
"were",
|
|
4181
|
+
"what",
|
|
4182
|
+
"when",
|
|
4183
|
+
"where",
|
|
4184
|
+
"which",
|
|
4185
|
+
"while",
|
|
4186
|
+
"will",
|
|
4187
|
+
"with",
|
|
4188
|
+
"without",
|
|
4189
|
+
"would",
|
|
4190
|
+
"your",
|
|
4191
|
+
"yours"
|
|
4192
|
+
]);
|
|
4193
|
+
}
|
|
4194
|
+
});
|
|
4195
|
+
|
|
3502
4196
|
// src/radiant/types.ts
|
|
3503
4197
|
function isScored(s) {
|
|
3504
4198
|
return typeof s === "number";
|
|
@@ -3550,7 +4244,11 @@ var init_math = __esm({
|
|
|
3550
4244
|
async function interpretPatterns(input) {
|
|
3551
4245
|
const prompt = buildInterpretationPrompt(input);
|
|
3552
4246
|
const raw = await input.ai.complete(prompt, "Analyze the activity and produce the read.");
|
|
3553
|
-
const
|
|
4247
|
+
const canonicalNames = [
|
|
4248
|
+
...input.canonicalPatterns ?? [],
|
|
4249
|
+
...input.declaredVocabulary?.allNames ?? []
|
|
4250
|
+
];
|
|
4251
|
+
const parsed = parseInterpretation(raw, canonicalNames, input.declaredVocabulary);
|
|
3554
4252
|
return {
|
|
3555
4253
|
patterns: parsed.patterns,
|
|
3556
4254
|
meaning: parsed.meaning,
|
|
@@ -3561,8 +4259,10 @@ async function interpretPatterns(input) {
|
|
|
3561
4259
|
function buildInterpretationPrompt(input) {
|
|
3562
4260
|
const signalSummary = formatSignalSummary(input.signals);
|
|
3563
4261
|
const eventSample = formatEventSample(input.events, 30);
|
|
3564
|
-
const canonicalList = (
|
|
3565
|
-
|
|
4262
|
+
const canonicalList = formatDeclaredVocabulary(
|
|
4263
|
+
input.declaredVocabulary,
|
|
4264
|
+
input.canonicalPatterns ?? []
|
|
4265
|
+
);
|
|
3566
4266
|
const compressedWorld = compressWorldmodel(input.worldmodelContent);
|
|
3567
4267
|
const cl = compressLens(input.lens);
|
|
3568
4268
|
const frame = input.lens.primary_frame;
|
|
@@ -3673,6 +4373,44 @@ Only recommend a move when the evidence actually calls for one.
|
|
|
3673
4373
|
Do NOT use these phrases anywhere in your output:
|
|
3674
4374
|
${forbiddenList}`;
|
|
3675
4375
|
}
|
|
4376
|
+
function formatDeclaredVocabulary(vocabulary, extraNames) {
|
|
4377
|
+
const aligned = vocabulary?.aligned ?? [];
|
|
4378
|
+
const drift = vocabulary?.drift ?? [];
|
|
4379
|
+
if (aligned.length === 0 && drift.length === 0 && extraNames.length === 0) {
|
|
4380
|
+
return 'No patterns have been named yet. Everything you observe is new \u2014 mark it type: "candidate".';
|
|
4381
|
+
}
|
|
4382
|
+
const parts = [];
|
|
4383
|
+
parts.push("## Declared vocabulary (use these names when you see matching evidence)");
|
|
4384
|
+
parts.push("");
|
|
4385
|
+
parts.push(
|
|
4386
|
+
'The worldmodel declares the patterns below. If your observation matches one of these, use the EXACT snake_case name shown and mark type: "canonical" \u2014 do not invent a new name for something that already has one.'
|
|
4387
|
+
);
|
|
4388
|
+
parts.push("");
|
|
4389
|
+
if (aligned.length > 0) {
|
|
4390
|
+
parts.push("### Aligned behaviors (positive patterns)");
|
|
4391
|
+
for (const p of aligned) {
|
|
4392
|
+
parts.push(`- \`${p.name}\` \u2014 ${p.prose}`);
|
|
4393
|
+
}
|
|
4394
|
+
parts.push("");
|
|
4395
|
+
}
|
|
4396
|
+
if (drift.length > 0) {
|
|
4397
|
+
parts.push("### Drift behaviors (negative patterns)");
|
|
4398
|
+
for (const p of drift) {
|
|
4399
|
+
parts.push(`- \`${p.name}\` \u2014 ${p.prose}`);
|
|
4400
|
+
}
|
|
4401
|
+
parts.push("");
|
|
4402
|
+
}
|
|
4403
|
+
if (extraNames.length > 0) {
|
|
4404
|
+
parts.push(
|
|
4405
|
+
`Additional canonical names (from prior runs or caller): ${extraNames.join(", ")}`
|
|
4406
|
+
);
|
|
4407
|
+
parts.push("");
|
|
4408
|
+
}
|
|
4409
|
+
parts.push(
|
|
4410
|
+
'If you observe something genuinely new that matches NO declared pattern, mark it type: "candidate" with a freshly-invented snake_case name.'
|
|
4411
|
+
);
|
|
4412
|
+
return parts.join("\n");
|
|
4413
|
+
}
|
|
3676
4414
|
function formatSignalSummary(signals) {
|
|
3677
4415
|
const lines = [];
|
|
3678
4416
|
const domains = ["life", "cyber", "joint"];
|
|
@@ -3698,7 +4436,7 @@ function formatEventSample(events, maxEvents) {
|
|
|
3698
4436
|
"${content}"`;
|
|
3699
4437
|
}).join("\n");
|
|
3700
4438
|
}
|
|
3701
|
-
function parseInterpretation(raw, canonicalNames) {
|
|
4439
|
+
function parseInterpretation(raw, canonicalNames, vocabulary) {
|
|
3702
4440
|
let meaning = "";
|
|
3703
4441
|
let move = "";
|
|
3704
4442
|
let patternsArray = [];
|
|
@@ -3728,14 +4466,23 @@ function parseInterpretation(raw, canonicalNames) {
|
|
|
3728
4466
|
const patterns = [];
|
|
3729
4467
|
for (const item of patternsArray) {
|
|
3730
4468
|
if (!isPatternLike(item)) continue;
|
|
3731
|
-
const
|
|
4469
|
+
const rawName = String(item.name ?? "unnamed");
|
|
4470
|
+
const description = String(item.description ?? "");
|
|
3732
4471
|
const ev = item.evidence;
|
|
3733
|
-
|
|
4472
|
+
let name = rawName;
|
|
4473
|
+
let isCanonical = item.type === "canonical" || canonicalSet.has(rawName.toLowerCase());
|
|
4474
|
+
if (!isCanonical && vocabulary) {
|
|
4475
|
+
const matched = matchDeclaredPattern(rawName, description, vocabulary);
|
|
4476
|
+
if (matched) {
|
|
4477
|
+
name = matched.name;
|
|
4478
|
+
isCanonical = true;
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
3734
4481
|
patterns.push({
|
|
3735
|
-
name
|
|
4482
|
+
name,
|
|
3736
4483
|
type: isCanonical ? "canonical" : "candidate",
|
|
3737
|
-
declaredAs: isCanonical ?
|
|
3738
|
-
description
|
|
4484
|
+
declaredAs: isCanonical ? name : void 0,
|
|
4485
|
+
description,
|
|
3739
4486
|
evidence: {
|
|
3740
4487
|
signals: Array.isArray(ev?.signals) ? ev.signals.map(String) : [],
|
|
3741
4488
|
events: Array.isArray(ev?.events) ? ev.events.map(String) : [],
|
|
@@ -3753,6 +4500,7 @@ var init_patterns = __esm({
|
|
|
3753
4500
|
"src/radiant/core/patterns.ts"() {
|
|
3754
4501
|
"use strict";
|
|
3755
4502
|
init_compress();
|
|
4503
|
+
init_vocabulary();
|
|
3756
4504
|
}
|
|
3757
4505
|
});
|
|
3758
4506
|
|
|
@@ -4071,10 +4819,24 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
|
4071
4819
|
} catch {
|
|
4072
4820
|
}
|
|
4073
4821
|
}
|
|
4822
|
+
const linearKey = process.env.LINEAR_API_KEY;
|
|
4823
|
+
if (linearKey) {
|
|
4824
|
+
try {
|
|
4825
|
+
const linear = await fetchLinearActivity(linearKey, { windowDays });
|
|
4826
|
+
events.push(...linear.events);
|
|
4827
|
+
adapterSignals += "\n\n" + formatLinearSignalsForPrompt(linear.signals);
|
|
4828
|
+
activeAdapters.push("linear");
|
|
4829
|
+
} catch {
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4074
4832
|
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
4833
|
+
if (input.personalUser) {
|
|
4834
|
+
events = filterEventsByUser(events, input.personalUser);
|
|
4835
|
+
}
|
|
4075
4836
|
const classified = classifyEvents(events);
|
|
4076
4837
|
const signals = extractSignals(classified);
|
|
4077
4838
|
const scores = computeScores(signals, input.worldmodelContent !== "");
|
|
4839
|
+
const declaredVocabulary = extractDeclaredVocabulary(worldmodelContent);
|
|
4078
4840
|
const { patterns, meaning, move } = await interpretPatterns({
|
|
4079
4841
|
signals,
|
|
4080
4842
|
events: classified,
|
|
@@ -4082,6 +4844,7 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
|
4082
4844
|
lens,
|
|
4083
4845
|
ai: input.ai,
|
|
4084
4846
|
canonicalPatterns: input.canonicalPatterns,
|
|
4847
|
+
declaredVocabulary,
|
|
4085
4848
|
statedIntent: [statedIntent, adapterSignals, priorReadContext].filter(Boolean).join("\n\n") || void 0
|
|
4086
4849
|
});
|
|
4087
4850
|
const rewrittenPatterns = patterns.map((p) => lens.rewrite(p));
|
|
@@ -4136,6 +4899,10 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
|
4136
4899
|
worldStack
|
|
4137
4900
|
};
|
|
4138
4901
|
}
|
|
4902
|
+
function filterEventsByUser(events, username) {
|
|
4903
|
+
const target = username.toLowerCase();
|
|
4904
|
+
return events.filter((e) => e.actor.id.toLowerCase() === target);
|
|
4905
|
+
}
|
|
4139
4906
|
function computeScores(signals, worldmodelLoaded) {
|
|
4140
4907
|
const gate = DEFAULT_EVIDENCE_GATE;
|
|
4141
4908
|
const lifeSignals = signals.filter((s) => s.domain === "life");
|
|
@@ -4191,12 +4958,14 @@ var init_emergent = __esm({
|
|
|
4191
4958
|
init_discord();
|
|
4192
4959
|
init_slack();
|
|
4193
4960
|
init_notion();
|
|
4961
|
+
init_linear();
|
|
4194
4962
|
init_discovery();
|
|
4195
4963
|
init_exocortex();
|
|
4196
4964
|
init_palace();
|
|
4197
4965
|
init_compress();
|
|
4198
4966
|
init_governance();
|
|
4199
4967
|
init_signals();
|
|
4968
|
+
init_vocabulary();
|
|
4200
4969
|
init_math();
|
|
4201
4970
|
init_patterns();
|
|
4202
4971
|
init_renderer();
|
|
@@ -4251,22 +5020,22 @@ __export(server_exports, {
|
|
|
4251
5020
|
startRadiantMcp: () => startRadiantMcp
|
|
4252
5021
|
});
|
|
4253
5022
|
function loadWorldmodelContent(worldsPath) {
|
|
4254
|
-
const resolved = (0,
|
|
4255
|
-
if (!(0,
|
|
5023
|
+
const resolved = (0, import_path6.resolve)(worldsPath);
|
|
5024
|
+
if (!(0, import_fs6.existsSync)(resolved)) {
|
|
4256
5025
|
throw new Error(`Worlds path not found: ${resolved}`);
|
|
4257
5026
|
}
|
|
4258
|
-
const stat = (0,
|
|
5027
|
+
const stat = (0, import_fs6.statSync)(resolved);
|
|
4259
5028
|
if (stat.isFile()) {
|
|
4260
|
-
return (0,
|
|
5029
|
+
return (0, import_fs6.readFileSync)(resolved, "utf-8");
|
|
4261
5030
|
}
|
|
4262
5031
|
if (stat.isDirectory()) {
|
|
4263
|
-
const files = (0,
|
|
4264
|
-
(f) => (0,
|
|
5032
|
+
const files = (0, import_fs6.readdirSync)(resolved).filter(
|
|
5033
|
+
(f) => (0, import_path6.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
|
|
4265
5034
|
).sort();
|
|
4266
5035
|
if (files.length === 0) {
|
|
4267
5036
|
throw new Error(`No worldmodel files found in ${resolved}`);
|
|
4268
5037
|
}
|
|
4269
|
-
return files.map((f) => (0,
|
|
5038
|
+
return files.map((f) => (0, import_fs6.readFileSync)((0, import_path6.join)(resolved, f), "utf-8")).join("\n\n---\n\n");
|
|
4270
5039
|
}
|
|
4271
5040
|
throw new Error(`Worlds path is neither a file nor directory: ${resolved}`);
|
|
4272
5041
|
}
|
|
@@ -4285,12 +5054,12 @@ async function startRadiantMcp(args) {
|
|
|
4285
5054
|
const server = new RadiantMcpServer({ worldsPath, lensId, model });
|
|
4286
5055
|
await server.start();
|
|
4287
5056
|
}
|
|
4288
|
-
var
|
|
5057
|
+
var import_fs6, import_path6, TOOLS, RadiantMcpServer;
|
|
4289
5058
|
var init_server = __esm({
|
|
4290
5059
|
"src/radiant/mcp/server.ts"() {
|
|
4291
5060
|
"use strict";
|
|
4292
|
-
|
|
4293
|
-
|
|
5061
|
+
import_fs6 = require("fs");
|
|
5062
|
+
import_path6 = require("path");
|
|
4294
5063
|
init_think();
|
|
4295
5064
|
init_emergent();
|
|
4296
5065
|
init_ai();
|
|
@@ -4518,18 +5287,22 @@ var init_server = __esm({
|
|
|
4518
5287
|
// src/cli/radiant.ts
|
|
4519
5288
|
var radiant_exports = {};
|
|
4520
5289
|
__export(radiant_exports, {
|
|
4521
|
-
|
|
5290
|
+
checkScopeConsent: () => checkScopeConsent,
|
|
5291
|
+
main: () => main,
|
|
5292
|
+
parseArgs: () => parseArgs
|
|
4522
5293
|
});
|
|
4523
5294
|
module.exports = __toCommonJS(radiant_exports);
|
|
4524
|
-
var
|
|
4525
|
-
var
|
|
5295
|
+
var import_fs7 = require("fs");
|
|
5296
|
+
var import_path7 = require("path");
|
|
4526
5297
|
init_think();
|
|
4527
5298
|
init_emergent();
|
|
4528
5299
|
init_ai();
|
|
4529
5300
|
init_scopes();
|
|
4530
5301
|
init_exocortex();
|
|
4531
5302
|
init_lenses();
|
|
5303
|
+
init_discovery();
|
|
4532
5304
|
var RED = "\x1B[31m";
|
|
5305
|
+
var GREEN = "\x1B[32m";
|
|
4533
5306
|
var DIM = "\x1B[2m";
|
|
4534
5307
|
var BOLD = "\x1B[1m";
|
|
4535
5308
|
var YELLOW = "\x1B[33m";
|
|
@@ -4537,6 +5310,9 @@ var RESET = "\x1B[0m";
|
|
|
4537
5310
|
var USAGE = `
|
|
4538
5311
|
${BOLD}neuroverse radiant${RESET} \u2014 behavioral intelligence for collaboration systems
|
|
4539
5312
|
|
|
5313
|
+
${BOLD}Setup:${RESET}
|
|
5314
|
+
init Scaffold a Mind Palace in the current directory
|
|
5315
|
+
|
|
4540
5316
|
${BOLD}Stage A (voice layer):${RESET}
|
|
4541
5317
|
think Send a query through the worldmodel + lens \u2192 AI-framed response
|
|
4542
5318
|
|
|
@@ -4547,19 +5323,46 @@ ${BOLD}Stage B (behavioral analysis, coming soon):${RESET}
|
|
|
4547
5323
|
lenses List or describe available rendering lenses
|
|
4548
5324
|
|
|
4549
5325
|
${BOLD}Usage:${RESET}
|
|
5326
|
+
neuroverse radiant init (scaffolds ./mind-palace/)
|
|
5327
|
+
neuroverse radiant init ./my-palace (custom path)
|
|
4550
5328
|
neuroverse radiant think --lens auki-builder --worlds ./worlds/ --query "What is our biggest risk?"
|
|
4551
5329
|
neuroverse radiant think --lens auki-builder --worlds ./worlds/ < prompt.txt
|
|
4552
5330
|
neuroverse radiant emergent aukiverse/posemesh --lens auki-builder --worlds ./worlds/
|
|
4553
5331
|
neuroverse radiant emergent aukiverse/posemesh --lens auki-builder --worlds ./worlds/ --exocortex ~/exocortex/
|
|
5332
|
+
neuroverse radiant emergent aukilabs/posemesh --personal --user alice
|
|
5333
|
+
neuroverse radiant emergent aukilabs/ --entire-org --lens auki-builder --worlds ./worlds/
|
|
4554
5334
|
neuroverse radiant lenses list
|
|
4555
5335
|
neuroverse radiant lenses describe auki-builder
|
|
4556
5336
|
|
|
5337
|
+
${BOLD}Read modes:${RESET}
|
|
5338
|
+
${BOLD}Default (team):${RESET} reads all contributors in the given scope.
|
|
5339
|
+
${BOLD}--personal --user <login>:${RESET} reads ONLY that user's activity.
|
|
5340
|
+
A local, private facilitator \u2014 no one else is observed. Works against
|
|
5341
|
+
any scope; an org scope with --personal is fine.
|
|
5342
|
+
${BOLD}--entire-org (gated):${RESET} org-wide scope observes every contributor
|
|
5343
|
+
across every repo. This is a global-observer stance and is opt-in.
|
|
5344
|
+
\`radiant emergent <org>/\` without --entire-org will refuse and show
|
|
5345
|
+
you the three choices (single repo, --personal, or explicit opt-in).
|
|
5346
|
+
|
|
5347
|
+
${BOLD}Auto-discovery:${RESET}
|
|
5348
|
+
You do not need to clone the target repo.
|
|
5349
|
+
|
|
5350
|
+
radiant emergent NeuroverseOS/ \u2192 probes github.com/NeuroverseOS/worlds
|
|
5351
|
+
radiant emergent aukiverse/posemesh \u2192 probes github.com/aukiverse/worlds
|
|
5352
|
+
|
|
5353
|
+
The scope argument itself is enough. Discovery also picks up
|
|
5354
|
+
~/.neuroverse/worlds/ (personal), the org from your current clone's
|
|
5355
|
+
.git/config (if any), and ./worlds/ (this repo).
|
|
5356
|
+
|
|
5357
|
+
Set NEUROVERSE_NO_ORG=1 to disable org probing for a single run.
|
|
5358
|
+
|
|
4557
5359
|
${BOLD}Environment:${RESET}
|
|
4558
5360
|
ANTHROPIC_API_KEY Required for AI commands (think, emergent, decision)
|
|
4559
5361
|
RADIANT_WORLDS Default worlds directory (overridden by --worlds)
|
|
4560
5362
|
RADIANT_LENS Default lens id (overridden by --lens)
|
|
4561
5363
|
RADIANT_MODEL AI model override (default: claude-sonnet-4-20250514)
|
|
4562
5364
|
RADIANT_EXOCORTEX Default exocortex directory (overridden by --exocortex)
|
|
5365
|
+
RADIANT_USER Default personal-mode user (overridden by --user)
|
|
4563
5366
|
`.trim();
|
|
4564
5367
|
function parseArgs(argv) {
|
|
4565
5368
|
const result = {
|
|
@@ -4571,8 +5374,12 @@ function parseArgs(argv) {
|
|
|
4571
5374
|
exocortex: void 0,
|
|
4572
5375
|
teamExocortex: void 0,
|
|
4573
5376
|
view: void 0,
|
|
5377
|
+
user: void 0,
|
|
5378
|
+
personal: false,
|
|
5379
|
+
entireOrg: false,
|
|
4574
5380
|
json: false,
|
|
4575
5381
|
help: false,
|
|
5382
|
+
force: false,
|
|
4576
5383
|
rest: []
|
|
4577
5384
|
};
|
|
4578
5385
|
let i = 0;
|
|
@@ -4604,9 +5411,22 @@ function parseArgs(argv) {
|
|
|
4604
5411
|
case "--view":
|
|
4605
5412
|
result.view = argv[++i];
|
|
4606
5413
|
break;
|
|
5414
|
+
case "--user":
|
|
5415
|
+
result.user = argv[++i];
|
|
5416
|
+
break;
|
|
5417
|
+
case "--personal":
|
|
5418
|
+
result.personal = true;
|
|
5419
|
+
break;
|
|
5420
|
+
case "--entire-org":
|
|
5421
|
+
result.entireOrg = true;
|
|
5422
|
+
break;
|
|
4607
5423
|
case "--json":
|
|
4608
5424
|
result.json = true;
|
|
4609
5425
|
break;
|
|
5426
|
+
case "--force":
|
|
5427
|
+
case "-f":
|
|
5428
|
+
result.force = true;
|
|
5429
|
+
break;
|
|
4610
5430
|
case "--help":
|
|
4611
5431
|
case "-h":
|
|
4612
5432
|
result.help = true;
|
|
@@ -4620,17 +5440,17 @@ function parseArgs(argv) {
|
|
|
4620
5440
|
return result;
|
|
4621
5441
|
}
|
|
4622
5442
|
function loadWorldmodelContent2(worldsPath) {
|
|
4623
|
-
const resolved = (0,
|
|
4624
|
-
if (!(0,
|
|
5443
|
+
const resolved = (0, import_path7.resolve)(worldsPath);
|
|
5444
|
+
if (!(0, import_fs7.existsSync)(resolved)) {
|
|
4625
5445
|
throw new Error(`Worlds path not found: ${resolved}`);
|
|
4626
5446
|
}
|
|
4627
|
-
const stat = (0,
|
|
5447
|
+
const stat = (0, import_fs7.statSync)(resolved);
|
|
4628
5448
|
if (stat.isFile()) {
|
|
4629
|
-
return (0,
|
|
5449
|
+
return (0, import_fs7.readFileSync)(resolved, "utf-8");
|
|
4630
5450
|
}
|
|
4631
5451
|
if (stat.isDirectory()) {
|
|
4632
|
-
const files = (0,
|
|
4633
|
-
(f) => (0,
|
|
5452
|
+
const files = (0, import_fs7.readdirSync)(resolved).filter(
|
|
5453
|
+
(f) => (0, import_path7.extname)(f) === ".md" && (f.endsWith(".worldmodel.md") || f.endsWith(".nv-world.md"))
|
|
4634
5454
|
).sort();
|
|
4635
5455
|
if (files.length === 0) {
|
|
4636
5456
|
throw new Error(
|
|
@@ -4638,27 +5458,55 @@ function loadWorldmodelContent2(worldsPath) {
|
|
|
4638
5458
|
);
|
|
4639
5459
|
}
|
|
4640
5460
|
return files.map((f) => {
|
|
4641
|
-
const content = (0,
|
|
5461
|
+
const content = (0, import_fs7.readFileSync)((0, import_path7.join)(resolved, f), "utf-8");
|
|
4642
5462
|
return `<!-- worldmodel: ${f} -->
|
|
4643
5463
|
${content}`;
|
|
4644
5464
|
}).join("\n\n---\n\n");
|
|
4645
5465
|
}
|
|
4646
5466
|
throw new Error(`Worlds path is neither a file nor a directory: ${resolved}`);
|
|
4647
5467
|
}
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
5468
|
+
function resolveWorldmodelContent(explicitPath, scopeOwner) {
|
|
5469
|
+
if (explicitPath) {
|
|
5470
|
+
return loadWorldmodelContent2(explicitPath);
|
|
5471
|
+
}
|
|
5472
|
+
const stack = discoverWorlds({
|
|
5473
|
+
repoDir: process.cwd(),
|
|
5474
|
+
scopeOwner
|
|
5475
|
+
});
|
|
5476
|
+
if (stack.worlds.length === 0) {
|
|
5477
|
+
const scopeLine = scopeOwner ? ` 3. github:${scopeOwner}/worlds (from scope arg)
|
|
5478
|
+
` : "";
|
|
5479
|
+
const ext = scopeOwner ? 4 : 3;
|
|
5480
|
+
const repo = scopeOwner ? 5 : 4;
|
|
4651
5481
|
process.stderr.write(
|
|
4652
|
-
`${RED}Error:${RESET}
|
|
4653
|
-
${DIM}
|
|
5482
|
+
`${RED}Error:${RESET} No worldmodel found.
|
|
5483
|
+
${DIM}Tried (in order):
|
|
5484
|
+
1. ~/.neuroverse/worlds/ (user tier)
|
|
5485
|
+
2. github:<owner>/worlds (org auto-detect from git remote)
|
|
5486
|
+
` + scopeLine + ` ${ext}. .neuroverse/config.json extends (explicit shared worlds)
|
|
5487
|
+
${repo}. ./worlds/ or ./.neuroverse/worlds/ (repo tier)
|
|
5488
|
+
|
|
5489
|
+
Pass --worlds <dir> or set RADIANT_WORLDS to specify explicitly.
|
|
5490
|
+
Or run against a <scope>/ where github.com/<scope>/worlds exists.${RESET}
|
|
4654
5491
|
`
|
|
4655
5492
|
);
|
|
4656
5493
|
process.exit(1);
|
|
4657
5494
|
}
|
|
4658
|
-
|
|
4659
|
-
|
|
5495
|
+
process.stderr.write(`${DIM}${formatActiveWorlds(stack)}${RESET}
|
|
5496
|
+
|
|
5497
|
+
`);
|
|
5498
|
+
for (const warning of stack.warnings) {
|
|
5499
|
+
process.stderr.write(`${YELLOW}\u26A0${RESET} ${warning}
|
|
5500
|
+
`);
|
|
5501
|
+
}
|
|
5502
|
+
return stack.combinedContent;
|
|
5503
|
+
}
|
|
5504
|
+
async function cmdThink(args) {
|
|
5505
|
+
const lensId = args.lens ?? process.env.RADIANT_LENS;
|
|
5506
|
+
if (!lensId) {
|
|
4660
5507
|
process.stderr.write(
|
|
4661
|
-
`${RED}Error:${RESET} --
|
|
5508
|
+
`${RED}Error:${RESET} --lens <id> or RADIANT_LENS required.
|
|
5509
|
+
${DIM}Available lenses: ${listLenses().join(", ")}${RESET}
|
|
4662
5510
|
`
|
|
4663
5511
|
);
|
|
4664
5512
|
process.exit(1);
|
|
@@ -4677,7 +5525,7 @@ ${DIM}Set it to your Anthropic API key to use Radiant's AI features.${RESET}
|
|
|
4677
5525
|
query = args.rest.join(" ");
|
|
4678
5526
|
}
|
|
4679
5527
|
if (!query && !process.stdin.isTTY) {
|
|
4680
|
-
query = (0,
|
|
5528
|
+
query = (0, import_fs7.readFileSync)(0, "utf-8").trim();
|
|
4681
5529
|
}
|
|
4682
5530
|
if (!query) {
|
|
4683
5531
|
process.stderr.write(
|
|
@@ -4687,12 +5535,12 @@ ${DIM}Use --query "...", pass as trailing args, or pipe via stdin.${RESET}
|
|
|
4687
5535
|
);
|
|
4688
5536
|
process.exit(1);
|
|
4689
5537
|
}
|
|
4690
|
-
const
|
|
5538
|
+
const explicitWorldsPath = args.worlds ?? process.env.RADIANT_WORLDS;
|
|
5539
|
+
const worldmodelContent = resolveWorldmodelContent(explicitWorldsPath);
|
|
4691
5540
|
const model = args.model ?? process.env.RADIANT_MODEL;
|
|
4692
5541
|
const ai = createAnthropicAI(apiKey, model || void 0);
|
|
4693
5542
|
process.stderr.write(
|
|
4694
|
-
`${DIM}
|
|
4695
|
-
${DIM}Lens: ${lensId}${RESET}
|
|
5543
|
+
`${DIM}Lens: ${lensId}${RESET}
|
|
4696
5544
|
${DIM}Model: ${model ?? "claude-sonnet-4-20250514 (default)"}${RESET}
|
|
4697
5545
|
|
|
4698
5546
|
`
|
|
@@ -4736,6 +5584,15 @@ ${DIM}Model: ${model ?? "claude-sonnet-4-20250514 (default)"}${RESET}
|
|
|
4736
5584
|
process.exit(2);
|
|
4737
5585
|
}
|
|
4738
5586
|
}
|
|
5587
|
+
function checkScopeConsent(input) {
|
|
5588
|
+
if (input.personal && !input.resolvedUser) {
|
|
5589
|
+
return { ok: false, reason: "personal_requires_user" };
|
|
5590
|
+
}
|
|
5591
|
+
if (input.scope.type === "org" && !input.entireOrg && !input.personal) {
|
|
5592
|
+
return { ok: false, reason: "org_requires_opt_in" };
|
|
5593
|
+
}
|
|
5594
|
+
return { ok: true };
|
|
5595
|
+
}
|
|
4739
5596
|
async function cmdEmergent(args) {
|
|
4740
5597
|
const scopeStr = args.rest[0];
|
|
4741
5598
|
if (!scopeStr) {
|
|
@@ -4746,19 +5603,48 @@ async function cmdEmergent(args) {
|
|
|
4746
5603
|
process.exit(1);
|
|
4747
5604
|
}
|
|
4748
5605
|
const scope = parseScope(scopeStr);
|
|
5606
|
+
const personalUser = args.user ?? process.env.RADIANT_USER;
|
|
5607
|
+
const consent = checkScopeConsent({
|
|
5608
|
+
scope,
|
|
5609
|
+
personal: args.personal,
|
|
5610
|
+
entireOrg: args.entireOrg,
|
|
5611
|
+
resolvedUser: personalUser
|
|
5612
|
+
});
|
|
5613
|
+
if (!consent.ok) {
|
|
5614
|
+
if (consent.reason === "personal_requires_user") {
|
|
5615
|
+
process.stderr.write(
|
|
5616
|
+
`${RED}Error:${RESET} --personal requires a GitHub username.
|
|
5617
|
+
${DIM}Pass --user <login> or set RADIANT_USER. Radiant will read
|
|
5618
|
+
only that user's activity \u2014 no one else is observed.${RESET}
|
|
5619
|
+
`
|
|
5620
|
+
);
|
|
5621
|
+
} else {
|
|
5622
|
+
process.stderr.write(
|
|
5623
|
+
`${YELLOW}\u26A0${RESET} ${BOLD}"${scope.owner}" is an org-wide scope.${RESET}
|
|
5624
|
+
|
|
5625
|
+
${DIM}This reads activity across ALL repos in the org \u2014 a global-observer
|
|
5626
|
+
pattern that some teams consider offside with decentralization and
|
|
5627
|
+
cognitive-liberty principles. It's opt-in for that reason.${RESET}
|
|
5628
|
+
|
|
5629
|
+
Three ways forward:
|
|
5630
|
+
${GREEN}1.${RESET} Scope to a single repo (recommended default):
|
|
5631
|
+
radiant emergent ${scope.owner}/<repo>
|
|
5632
|
+
|
|
5633
|
+
${GREEN}2.${RESET} Read only your own activity (personal mode):
|
|
5634
|
+
radiant emergent ${scope.owner}/ --personal --user <your-login>
|
|
5635
|
+
|
|
5636
|
+
${GREEN}3.${RESET} Explicitly opt in to org-wide observation:
|
|
5637
|
+
radiant emergent ${scope.owner}/ --entire-org
|
|
5638
|
+
`
|
|
5639
|
+
);
|
|
5640
|
+
}
|
|
5641
|
+
process.exit(1);
|
|
5642
|
+
}
|
|
4749
5643
|
const lensId = args.lens ?? process.env.RADIANT_LENS;
|
|
4750
5644
|
if (!lensId) {
|
|
4751
5645
|
process.stderr.write(
|
|
4752
5646
|
`${RED}Error:${RESET} --lens <id> or RADIANT_LENS required.
|
|
4753
5647
|
${DIM}Available lenses: ${listLenses().join(", ")}${RESET}
|
|
4754
|
-
`
|
|
4755
|
-
);
|
|
4756
|
-
process.exit(1);
|
|
4757
|
-
}
|
|
4758
|
-
const worldsPath = args.worlds ?? process.env.RADIANT_WORLDS;
|
|
4759
|
-
if (!worldsPath) {
|
|
4760
|
-
process.stderr.write(
|
|
4761
|
-
`${RED}Error:${RESET} --worlds <dir> or RADIANT_WORLDS required.
|
|
4762
5648
|
`
|
|
4763
5649
|
);
|
|
4764
5650
|
process.exit(1);
|
|
@@ -4780,7 +5666,11 @@ ${DIM}Set it to a GitHub PAT with repo read access.${RESET}
|
|
|
4780
5666
|
);
|
|
4781
5667
|
process.exit(1);
|
|
4782
5668
|
}
|
|
4783
|
-
const
|
|
5669
|
+
const explicitWorldsPath = args.worlds ?? process.env.RADIANT_WORLDS;
|
|
5670
|
+
const worldmodelContent = resolveWorldmodelContent(
|
|
5671
|
+
explicitWorldsPath,
|
|
5672
|
+
scope.owner
|
|
5673
|
+
);
|
|
4784
5674
|
const model = args.model ?? process.env.RADIANT_MODEL;
|
|
4785
5675
|
const ai = createAnthropicAI(anthropicKey, model || void 0);
|
|
4786
5676
|
const view = args.view ?? process.env.RADIANT_VIEW ?? "community";
|
|
@@ -4798,8 +5688,11 @@ ${DIM}Set it to a GitHub PAT with repo read access.${RESET}
|
|
|
4798
5688
|
const ctx = readExocortex(exocortexPath);
|
|
4799
5689
|
exocortexStatus = summarizeExocortex(ctx);
|
|
4800
5690
|
}
|
|
5691
|
+
const scopeLabel = scope.type === "org" ? scope.owner + " (entire org)" : scope.owner + "/" + scope.repo;
|
|
5692
|
+
const modeLabel = args.personal ? `personal \u2014 only ${personalUser}'s activity` : "team \u2014 all contributors";
|
|
4801
5693
|
process.stderr.write(
|
|
4802
|
-
`${DIM}Scope: ${
|
|
5694
|
+
`${DIM}Scope: ${scopeLabel}${RESET}
|
|
5695
|
+
${DIM}Mode: ${modeLabel}${RESET}
|
|
4803
5696
|
${DIM}View: ${view}${RESET}
|
|
4804
5697
|
${DIM}Lens: ${lensId}${RESET}
|
|
4805
5698
|
${DIM}Model: ${model ?? "claude-sonnet-4-20250514 (default)"}${RESET}
|
|
@@ -4815,7 +5708,8 @@ ${DIM}Fetching activity...${RESET}
|
|
|
4815
5708
|
lensId,
|
|
4816
5709
|
ai,
|
|
4817
5710
|
windowDays: 14,
|
|
4818
|
-
exocortexPath: exocortexPath || void 0
|
|
5711
|
+
exocortexPath: exocortexPath || void 0,
|
|
5712
|
+
personalUser: args.personal ? personalUser : void 0
|
|
4819
5713
|
});
|
|
4820
5714
|
if (!result.voiceClean) {
|
|
4821
5715
|
process.stderr.write(
|
|
@@ -4917,6 +5811,204 @@ ${DIM}Use: lenses list | lenses describe <id>${RESET}
|
|
|
4917
5811
|
);
|
|
4918
5812
|
process.exit(1);
|
|
4919
5813
|
}
|
|
5814
|
+
var MIND_PALACE_FILES = {
|
|
5815
|
+
"README.md": `# Mind Palace
|
|
5816
|
+
|
|
5817
|
+
This is your Mind Palace \u2014 structured external memory that gives Radiant
|
|
5818
|
+
(and any agent you wire into it) persistent context about who you are,
|
|
5819
|
+
what you're working on, and what "on track" means for you.
|
|
5820
|
+
|
|
5821
|
+
Radiant reads these files before every run and writes each read back into
|
|
5822
|
+
\`reads/\`. Over time, \`knowledge.md\` accumulates what's persisted and what
|
|
5823
|
+
hasn't \u2014 the feedback loop that turns raw activity into named behavior.
|
|
5824
|
+
|
|
5825
|
+
## Files
|
|
5826
|
+
|
|
5827
|
+
- \`attention.md\` \u2014 what you're focused on **right now**
|
|
5828
|
+
- \`goals.md\` \u2014 what you're working toward
|
|
5829
|
+
- \`sprint.md\` \u2014 this week's focus
|
|
5830
|
+
- \`identity.md\` \u2014 who you are, what you value
|
|
5831
|
+
- \`worldmodels/\` \u2014 your thinking constitutions (drift + aligned behaviors)
|
|
5832
|
+
- \`reads/\` \u2014 dated Radiant reads (written by \`radiant emergent\`)
|
|
5833
|
+
- \`knowledge.md\` \u2014 accumulated pattern persistence across reads
|
|
5834
|
+
|
|
5835
|
+
## How to use
|
|
5836
|
+
|
|
5837
|
+
1. Fill in \`attention.md\`, \`goals.md\`, \`sprint.md\`, \`identity.md\` with
|
|
5838
|
+
your own words. A sentence each is enough to start \u2014 the files grow
|
|
5839
|
+
with you.
|
|
5840
|
+
2. Edit \`worldmodels/starter.worldmodel.md\`: add a few aligned behaviors
|
|
5841
|
+
(what on-track looks like) and drift behaviors (what off-track looks
|
|
5842
|
+
like). The sharper these are, the sharper Radiant's reads.
|
|
5843
|
+
3. Run \`neuroverse radiant emergent <owner/repo> --mind-palace .\` against
|
|
5844
|
+
the repo you want read. Radiant compares your stated intent (these
|
|
5845
|
+
files) to your observed activity (GitHub) and names the gap.
|
|
5846
|
+
|
|
5847
|
+
Edit freely. These files are yours.
|
|
5848
|
+
`,
|
|
5849
|
+
"attention.md": `# Attention
|
|
5850
|
+
|
|
5851
|
+
<!--
|
|
5852
|
+
What are you focused on RIGHT NOW? One paragraph. Updated as you shift.
|
|
5853
|
+
This is the file an AI agent reads at the start of a session to know
|
|
5854
|
+
what to help with today.
|
|
5855
|
+
-->
|
|
5856
|
+
|
|
5857
|
+
`,
|
|
5858
|
+
"goals.md": `# Goals
|
|
5859
|
+
|
|
5860
|
+
<!--
|
|
5861
|
+
What are you working toward? Bullet points welcome.
|
|
5862
|
+
Longer horizon than attention \u2014 months, not days.
|
|
5863
|
+
-->
|
|
5864
|
+
|
|
5865
|
+
-
|
|
5866
|
+
`,
|
|
5867
|
+
"sprint.md": `# Sprint
|
|
5868
|
+
|
|
5869
|
+
<!--
|
|
5870
|
+
This week's focus. What do you want to ship or finish?
|
|
5871
|
+
Keep it short \u2014 five bullets max.
|
|
5872
|
+
-->
|
|
5873
|
+
|
|
5874
|
+
-
|
|
5875
|
+
`,
|
|
5876
|
+
"identity.md": `# Identity
|
|
5877
|
+
|
|
5878
|
+
<!--
|
|
5879
|
+
Who are you, what do you value, how do you work?
|
|
5880
|
+
This is the context an agent needs to not treat you like a stranger
|
|
5881
|
+
every time. Write it in your own voice.
|
|
5882
|
+
-->
|
|
5883
|
+
|
|
5884
|
+
`,
|
|
5885
|
+
"knowledge.md": `# Knowledge
|
|
5886
|
+
|
|
5887
|
+
<!--
|
|
5888
|
+
Radiant writes accumulated pattern persistence here across reads.
|
|
5889
|
+
Leave this file empty on day one \u2014 it fills up as \`radiant emergent\`
|
|
5890
|
+
runs accumulate.
|
|
5891
|
+
-->
|
|
5892
|
+
|
|
5893
|
+
`,
|
|
5894
|
+
"reads/.gitkeep": "",
|
|
5895
|
+
"worldmodels/starter.worldmodel.md": `# Starter Worldmodel
|
|
5896
|
+
|
|
5897
|
+
<!--
|
|
5898
|
+
Your thinking constitution. Radiant reads this to understand what
|
|
5899
|
+
"aligned" and "drift" mean for your work.
|
|
5900
|
+
|
|
5901
|
+
The sharper the Aligned/Drift Behaviors, the sharper Radiant's reads.
|
|
5902
|
+
When Radiant detects something matching a drift behavior below, it
|
|
5903
|
+
labels it with THAT name \u2014 it doesn't invent new ones.
|
|
5904
|
+
-->
|
|
5905
|
+
|
|
5906
|
+
## Mission
|
|
5907
|
+
|
|
5908
|
+
<!-- One sentence. What are you doing in the world? -->
|
|
5909
|
+
|
|
5910
|
+
|
|
5911
|
+
## Invariants
|
|
5912
|
+
|
|
5913
|
+
<!--
|
|
5914
|
+
Non-negotiable rules. If a decision violates one, it's blocked.
|
|
5915
|
+
Keep this list short \u2014 3 to 6 items. Each should be a hard no.
|
|
5916
|
+
-->
|
|
5917
|
+
|
|
5918
|
+
-
|
|
5919
|
+
|
|
5920
|
+
## Aligned Behaviors
|
|
5921
|
+
|
|
5922
|
+
<!--
|
|
5923
|
+
What "on track" looks like. One per line, phrased as a behavior.
|
|
5924
|
+
Radiant will use these as canonical pattern names when it sees
|
|
5925
|
+
matching evidence in your activity.
|
|
5926
|
+
|
|
5927
|
+
Example:
|
|
5928
|
+
- ships partial-but-working features rather than waiting for the full stack
|
|
5929
|
+
- writes decisions down before acting on them
|
|
5930
|
+
-->
|
|
5931
|
+
|
|
5932
|
+
-
|
|
5933
|
+
|
|
5934
|
+
## Drift Behaviors
|
|
5935
|
+
|
|
5936
|
+
<!--
|
|
5937
|
+
What "off track" looks like. Same format as Aligned.
|
|
5938
|
+
When Radiant detects drift, it will label it with these names \u2014 not
|
|
5939
|
+
make up new ones.
|
|
5940
|
+
|
|
5941
|
+
Example:
|
|
5942
|
+
- shipping pace outruns strategic decision-making
|
|
5943
|
+
- architecture decisions surface without context about why
|
|
5944
|
+
-->
|
|
5945
|
+
|
|
5946
|
+
-
|
|
5947
|
+
|
|
5948
|
+
## Signals
|
|
5949
|
+
|
|
5950
|
+
<!--
|
|
5951
|
+
Observable quantities you care about. Radiant scores activity
|
|
5952
|
+
against these \u2014 5 to 7 is the sweet spot.
|
|
5953
|
+
|
|
5954
|
+
Example:
|
|
5955
|
+
- shipping_velocity
|
|
5956
|
+
- decision_ownership
|
|
5957
|
+
- storytelling_cadence
|
|
5958
|
+
-->
|
|
5959
|
+
|
|
5960
|
+
-
|
|
5961
|
+
|
|
5962
|
+
## Decision Priorities
|
|
5963
|
+
|
|
5964
|
+
<!--
|
|
5965
|
+
When tradeoffs appear, these resolve them. Format: "A > B".
|
|
5966
|
+
|
|
5967
|
+
Example:
|
|
5968
|
+
- correctness > speed
|
|
5969
|
+
- clarity > cleverness
|
|
5970
|
+
-->
|
|
5971
|
+
|
|
5972
|
+
-
|
|
5973
|
+
`
|
|
5974
|
+
};
|
|
5975
|
+
async function cmdInit(args) {
|
|
5976
|
+
const targetDir = (0, import_path7.resolve)(args.rest[0] ?? "./mind-palace");
|
|
5977
|
+
const existed = (0, import_fs7.existsSync)(targetDir);
|
|
5978
|
+
if (existed && !args.force) {
|
|
5979
|
+
const entries = (0, import_fs7.readdirSync)(targetDir);
|
|
5980
|
+
if (entries.length > 0) {
|
|
5981
|
+
process.stderr.write(
|
|
5982
|
+
`${RED}Error:${RESET} ${targetDir} already exists and is not empty.
|
|
5983
|
+
${DIM}Use --force to write into it anyway (existing files will be overwritten).${RESET}
|
|
5984
|
+
`
|
|
5985
|
+
);
|
|
5986
|
+
process.exit(1);
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
(0, import_fs7.mkdirSync)(targetDir, { recursive: true });
|
|
5990
|
+
(0, import_fs7.mkdirSync)((0, import_path7.join)(targetDir, "reads"), { recursive: true });
|
|
5991
|
+
(0, import_fs7.mkdirSync)((0, import_path7.join)(targetDir, "worldmodels"), { recursive: true });
|
|
5992
|
+
for (const [relPath, content] of Object.entries(MIND_PALACE_FILES)) {
|
|
5993
|
+
const fullPath = (0, import_path7.join)(targetDir, relPath);
|
|
5994
|
+
(0, import_fs7.mkdirSync)((0, import_path7.resolve)(fullPath, ".."), { recursive: true });
|
|
5995
|
+
(0, import_fs7.writeFileSync)(fullPath, content, "utf-8");
|
|
5996
|
+
}
|
|
5997
|
+
process.stdout.write(
|
|
5998
|
+
`${GREEN}\u2713${RESET} Mind Palace scaffolded at ${BOLD}${targetDir}${RESET}
|
|
5999
|
+
|
|
6000
|
+
${DIM}Next steps:${RESET}
|
|
6001
|
+
1. Edit ${targetDir}/attention.md \u2014 what you're focused on right now
|
|
6002
|
+
2. Edit ${targetDir}/worldmodels/starter.worldmodel.md \u2014 add a few
|
|
6003
|
+
aligned and drift behaviors
|
|
6004
|
+
3. Run: neuroverse radiant emergent <owner/repo> \\
|
|
6005
|
+
--worlds ${targetDir}/worldmodels \\
|
|
6006
|
+
--exocortex ${targetDir}
|
|
6007
|
+
|
|
6008
|
+
${DIM}Files are yours. Edit freely.${RESET}
|
|
6009
|
+
`
|
|
6010
|
+
);
|
|
6011
|
+
}
|
|
4920
6012
|
async function main(argv) {
|
|
4921
6013
|
const args = parseArgs(argv);
|
|
4922
6014
|
if (args.help || !args.subcommand) {
|
|
@@ -4924,6 +6016,8 @@ async function main(argv) {
|
|
|
4924
6016
|
return;
|
|
4925
6017
|
}
|
|
4926
6018
|
switch (args.subcommand) {
|
|
6019
|
+
case "init":
|
|
6020
|
+
return cmdInit(args);
|
|
4927
6021
|
case "think":
|
|
4928
6022
|
return cmdThink(args);
|
|
4929
6023
|
case "lenses":
|
|
@@ -4956,5 +6050,7 @@ async function main(argv) {
|
|
|
4956
6050
|
}
|
|
4957
6051
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4958
6052
|
0 && (module.exports = {
|
|
4959
|
-
|
|
6053
|
+
checkScopeConsent,
|
|
6054
|
+
main,
|
|
6055
|
+
parseArgs
|
|
4960
6056
|
});
|