@neuroverseos/governance 0.9.0 → 0.11.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/README.md +1 -1
- package/dist/adapters/autoresearch.cjs +19 -1
- package/dist/adapters/autoresearch.d.cts +1 -1
- package/dist/adapters/autoresearch.d.ts +1 -1
- package/dist/adapters/autoresearch.js +2 -2
- package/dist/adapters/deep-agents.cjs +19 -1
- package/dist/adapters/deep-agents.d.cts +2 -2
- package/dist/adapters/deep-agents.d.ts +2 -2
- package/dist/adapters/deep-agents.js +2 -2
- package/dist/adapters/express.cjs +19 -1
- package/dist/adapters/express.d.cts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +2 -2
- package/dist/adapters/github.cjs +19 -1
- package/dist/adapters/github.d.cts +2 -2
- package/dist/adapters/github.d.ts +2 -2
- package/dist/adapters/github.js +2 -2
- package/dist/adapters/index.cjs +19 -1
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.js +8 -8
- package/dist/adapters/langchain.cjs +19 -1
- package/dist/adapters/langchain.d.cts +2 -2
- package/dist/adapters/langchain.d.ts +2 -2
- package/dist/adapters/langchain.js +2 -2
- package/dist/adapters/mentraos.cjs +19 -1
- package/dist/adapters/mentraos.d.cts +2 -2
- package/dist/adapters/mentraos.d.ts +2 -2
- package/dist/adapters/mentraos.js +2 -2
- package/dist/adapters/openai.cjs +19 -1
- package/dist/adapters/openai.d.cts +2 -2
- package/dist/adapters/openai.d.ts +2 -2
- package/dist/adapters/openai.js +2 -2
- package/dist/adapters/openclaw.cjs +19 -1
- package/dist/adapters/openclaw.d.cts +2 -2
- package/dist/adapters/openclaw.d.ts +2 -2
- package/dist/adapters/openclaw.js +2 -2
- package/dist/admin/index.cjs +19 -1
- package/dist/admin/index.js +1 -1
- package/dist/audit-CRJOB4CP.js +93 -0
- package/dist/audit-behavior-C62FdRAC.d.cts +100 -0
- package/dist/audit-behavior-DFy7LeYv.d.ts +100 -0
- package/dist/{behavioral-SPWPGYXL.js → behavioral-4TKMHZQZ.js} +2 -2
- package/dist/{chunk-OQU65525.js → chunk-24YW7BHC.js} +1 -1
- package/dist/{chunk-3ZWU7C43.js → chunk-2KTPIE57.js} +494 -14
- package/dist/{chunk-TJ5L2UTE.js → chunk-5K3LATTM.js} +1 -1
- package/dist/{chunk-HDNDL6D5.js → chunk-5LDBYOSJ.js} +1 -1
- package/dist/{chunk-FDPPZLSQ.js → chunk-5ZWKM7MO.js} +1 -1
- package/dist/{chunk-B3IIPTY3.js → chunk-6MB6TMAG.js} +1 -1
- package/dist/{chunk-IOVXB6QN.js → chunk-GXTAHCND.js} +1 -1
- package/dist/{chunk-FKQCPRKI.js → chunk-MAOIHKFO.js} +1 -1
- package/dist/{chunk-ZAF6JH23.js → chunk-MBOW6YXN.js} +19 -1
- package/dist/{chunk-A2UZTLRV.js → chunk-MLXKSX3L.js} +1 -1
- package/dist/{chunk-7FL3U7Z5.js → chunk-MWGEXHOD.js} +1 -1
- package/dist/{chunk-6CV4XG3J.js → chunk-QFDFAWZ6.js} +1 -1
- package/dist/{chunk-2VAWP6FI.js → chunk-RAS62JXV.js} +1 -1
- package/dist/{chunk-OTZU76DH.js → chunk-XAF3CYCW.js} +1 -1
- package/dist/{chunk-T6GMRZWC.js → chunk-XTYQCTDD.js} +1 -1
- package/dist/{chunk-TIXVEPS2.js → chunk-YN7OI5ZV.js} +1 -1
- package/dist/cli/neuroverse.cjs +999 -111
- package/dist/cli/neuroverse.js +16 -12
- package/dist/cli/plan.cjs +18 -0
- package/dist/cli/radiant.cjs +814 -17
- package/dist/cli/radiant.d.cts +44 -1
- package/dist/cli/radiant.d.ts +44 -1
- package/dist/cli/radiant.js +295 -7
- package/dist/cli/run.cjs +18 -0
- package/dist/cli/run.js +4 -4
- package/dist/{decision-flow-IJPNMVQK.js → decision-flow-5VI5YG6A.js} +2 -2
- package/dist/{demo-6W3YXLAX.js → demo-GYX6CYHC.js} +2 -2
- package/dist/engine/guard-engine.cjs +19 -1
- package/dist/engine/guard-engine.d.cts +21 -1
- package/dist/engine/guard-engine.d.ts +21 -1
- package/dist/engine/guard-engine.js +1 -1
- package/dist/{equity-penalties-CCO3GVHS.js → equity-penalties-NOM46NEO.js} +2 -2
- package/dist/{guard-IHJEKHL2.js → guard-PQ3SYV4Y.js} +3 -3
- package/dist/{guard-contract-ddiIPlOg.d.cts → guard-contract-Oznf-Kgq.d.cts} +32 -0
- package/dist/{guard-contract-q6HJAq3Q.d.ts → guard-contract-w_i_6gh-.d.ts} +32 -0
- package/dist/{impact-WIAM66IH.js → impact-LDJLTVRU.js} +3 -3
- package/dist/index.cjs +62 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +49 -8
- package/dist/{mcp-server-CKYBHXWK.js → mcp-server-W3MWSKD7.js} +2 -2
- package/dist/{playground-3TTBN7XD.js → playground-SSZRNUAF.js} +1 -1
- package/dist/radiant/index.cjs +517 -14
- package/dist/radiant/index.d.cts +180 -10
- package/dist/radiant/index.d.ts +180 -10
- package/dist/radiant/index.js +12 -2
- package/dist/{redteam-W644UMWN.js → redteam-KCULS7EW.js} +1 -1
- package/dist/{server-JKUBUK5H.js → server-EGRGGSM2.js} +2 -2
- package/dist/{session-FMAROEIE.js → session-PZLTL22G.js} +2 -2
- package/dist/{shared-PpalGKxc.d.cts → shared-BC8mOpt0.d.cts} +1 -1
- package/dist/{shared-DAzdfWtU.d.ts → shared-CP63gNNW.d.ts} +1 -1
- package/dist/{test-XDB2DH3L.js → test-LIHGWHBA.js} +1 -1
- package/dist/{trace-2YDNAXMK.js → trace-DC3D7XPD.js} +2 -2
- package/examples/radiant-weekly-workflow.yml +4 -1
- package/package.json +1 -1
- /package/dist/{doctor-XEMLO6UA.js → doctor-SIWQGTAO.js} +0 -0
package/dist/radiant/index.cjs
CHANGED
|
@@ -51,15 +51,19 @@ __export(radiant_exports, {
|
|
|
51
51
|
detectOrgExtendsSpec: () => detectOrgExtendsSpec,
|
|
52
52
|
discoverWorlds: () => discoverWorlds,
|
|
53
53
|
emergent: () => emergent,
|
|
54
|
+
extractDeclaredVocabulary: () => extractDeclaredVocabulary,
|
|
54
55
|
extractSignals: () => extractSignals,
|
|
55
56
|
fetchDiscordActivity: () => fetchDiscordActivity,
|
|
56
57
|
fetchGitHubActivity: () => fetchGitHubActivity,
|
|
57
58
|
fetchGitHubOrgActivity: () => fetchGitHubOrgActivity,
|
|
59
|
+
fetchLinearActivity: () => fetchLinearActivity,
|
|
58
60
|
fetchNotionActivity: () => fetchNotionActivity,
|
|
59
61
|
fetchSlackActivity: () => fetchSlackActivity,
|
|
62
|
+
filterEventsByUser: () => filterEventsByUser,
|
|
60
63
|
formatActiveWorlds: () => formatActiveWorlds,
|
|
61
64
|
formatDiscordSignalsForPrompt: () => formatDiscordSignalsForPrompt,
|
|
62
65
|
formatExocortexForPrompt: () => formatExocortexForPrompt,
|
|
66
|
+
formatLinearSignalsForPrompt: () => formatLinearSignalsForPrompt,
|
|
63
67
|
formatNotionSignalsForPrompt: () => formatNotionSignalsForPrompt,
|
|
64
68
|
formatPriorReadsForPrompt: () => formatPriorReadsForPrompt,
|
|
65
69
|
formatScope: () => formatScope,
|
|
@@ -75,6 +79,7 @@ __export(radiant_exports, {
|
|
|
75
79
|
listLenses: () => listLenses,
|
|
76
80
|
loadExtendsConfig: () => loadExtendsConfig,
|
|
77
81
|
loadPriorReads: () => loadPriorReads,
|
|
82
|
+
matchDeclaredPattern: () => matchDeclaredPattern,
|
|
78
83
|
parseExtendsSpec: () => parseExtendsSpec,
|
|
79
84
|
parseRemoteUrl: () => parseRemoteUrl,
|
|
80
85
|
parseRepoScope: () => parseRepoScope,
|
|
@@ -2040,11 +2045,398 @@ async function fetchNotionAPI(url, headers, init) {
|
|
|
2040
2045
|
return await res.json();
|
|
2041
2046
|
}
|
|
2042
2047
|
|
|
2048
|
+
// src/radiant/adapters/linear.ts
|
|
2049
|
+
async function fetchLinearActivity(apiKey, options = {}) {
|
|
2050
|
+
const windowDays = options.windowDays ?? 14;
|
|
2051
|
+
const maxIssues = options.maxIssues ?? 200;
|
|
2052
|
+
const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1e3);
|
|
2053
|
+
const sinceIso = since.toISOString();
|
|
2054
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
2055
|
+
const teamFilter = options.teamIds && options.teamIds.length > 0 ? `team: { id: { in: [${options.teamIds.map((t) => JSON.stringify(t)).join(", ")}] } }` : "";
|
|
2056
|
+
const issuesQuery = `
|
|
2057
|
+
query RadiantIssues($since: DateTimeOrDuration!, $first: Int!) {
|
|
2058
|
+
issues(
|
|
2059
|
+
filter: {
|
|
2060
|
+
updatedAt: { gte: $since }
|
|
2061
|
+
${teamFilter}
|
|
2062
|
+
}
|
|
2063
|
+
first: $first
|
|
2064
|
+
orderBy: updatedAt
|
|
2065
|
+
) {
|
|
2066
|
+
nodes {
|
|
2067
|
+
id
|
|
2068
|
+
identifier
|
|
2069
|
+
title
|
|
2070
|
+
url
|
|
2071
|
+
createdAt
|
|
2072
|
+
updatedAt
|
|
2073
|
+
completedAt
|
|
2074
|
+
canceledAt
|
|
2075
|
+
state { name type }
|
|
2076
|
+
assignee { id name email }
|
|
2077
|
+
creator { id name }
|
|
2078
|
+
team { id name }
|
|
2079
|
+
project { id name }
|
|
2080
|
+
cycle { id number startsAt endsAt }
|
|
2081
|
+
comments(first: 20) {
|
|
2082
|
+
nodes { id body createdAt user { id name } }
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
`;
|
|
2088
|
+
const cyclesQuery = `
|
|
2089
|
+
query RadiantCycles($since: DateTimeOrDuration!, $now: DateTimeOrDuration!) {
|
|
2090
|
+
cycles(
|
|
2091
|
+
filter: { endsAt: { gte: $since, lte: $now } }
|
|
2092
|
+
first: 20
|
|
2093
|
+
) {
|
|
2094
|
+
nodes {
|
|
2095
|
+
id
|
|
2096
|
+
number
|
|
2097
|
+
startsAt
|
|
2098
|
+
endsAt
|
|
2099
|
+
issueCountHistory
|
|
2100
|
+
completedIssueCountHistory
|
|
2101
|
+
team { id name }
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
`;
|
|
2106
|
+
const [issuesResponse, cyclesResponse] = await Promise.all([
|
|
2107
|
+
fetchLinearGraphQL(apiKey, issuesQuery, {
|
|
2108
|
+
since: sinceIso,
|
|
2109
|
+
first: maxIssues
|
|
2110
|
+
}),
|
|
2111
|
+
fetchLinearGraphQL(apiKey, cyclesQuery, {
|
|
2112
|
+
since: sinceIso,
|
|
2113
|
+
now: nowIso
|
|
2114
|
+
})
|
|
2115
|
+
]);
|
|
2116
|
+
const rawIssues = issuesResponse.issues?.nodes ?? [];
|
|
2117
|
+
const rawCycles = cyclesResponse.cycles?.nodes ?? [];
|
|
2118
|
+
const events = [];
|
|
2119
|
+
const assignees = /* @__PURE__ */ new Set();
|
|
2120
|
+
const projects = /* @__PURE__ */ new Map();
|
|
2121
|
+
let issuesCreated = 0;
|
|
2122
|
+
let issuesCompleted = 0;
|
|
2123
|
+
let issuesOpen = 0;
|
|
2124
|
+
let issuesStalled = 0;
|
|
2125
|
+
let commentsTotal = 0;
|
|
2126
|
+
const now = Date.now();
|
|
2127
|
+
const stallThresholdMs = 14 * 24 * 60 * 60 * 1e3;
|
|
2128
|
+
for (const issue of rawIssues) {
|
|
2129
|
+
const created = new Date(issue.createdAt);
|
|
2130
|
+
const updated = new Date(issue.updatedAt);
|
|
2131
|
+
const completed = issue.completedAt ? new Date(issue.completedAt) : null;
|
|
2132
|
+
const assigneeId = issue.assignee?.id ?? "unassigned";
|
|
2133
|
+
if (assigneeId !== "unassigned") assignees.add(assigneeId);
|
|
2134
|
+
if (issue.project) {
|
|
2135
|
+
projects.set(issue.project.name, (projects.get(issue.project.name) ?? 0) + 1);
|
|
2136
|
+
}
|
|
2137
|
+
const actor = {
|
|
2138
|
+
id: assigneeId,
|
|
2139
|
+
kind: "human",
|
|
2140
|
+
name: issue.assignee?.name ?? "unassigned"
|
|
2141
|
+
};
|
|
2142
|
+
if (created >= since) {
|
|
2143
|
+
issuesCreated++;
|
|
2144
|
+
events.push({
|
|
2145
|
+
id: `linear-created-${issue.id}`,
|
|
2146
|
+
timestamp: issue.createdAt,
|
|
2147
|
+
actor: {
|
|
2148
|
+
id: issue.creator?.id ?? "unknown",
|
|
2149
|
+
kind: "human",
|
|
2150
|
+
name: issue.creator?.name ?? "unknown"
|
|
2151
|
+
},
|
|
2152
|
+
kind: "issue_created",
|
|
2153
|
+
content: `[${issue.identifier}] ${issue.title}`,
|
|
2154
|
+
metadata: {
|
|
2155
|
+
issueId: issue.id,
|
|
2156
|
+
url: issue.url,
|
|
2157
|
+
team: issue.team?.name,
|
|
2158
|
+
project: issue.project?.name,
|
|
2159
|
+
state: issue.state?.name
|
|
2160
|
+
}
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
if (completed && completed >= since) {
|
|
2164
|
+
issuesCompleted++;
|
|
2165
|
+
events.push({
|
|
2166
|
+
id: `linear-completed-${issue.id}`,
|
|
2167
|
+
timestamp: issue.completedAt,
|
|
2168
|
+
actor,
|
|
2169
|
+
kind: "issue_completed",
|
|
2170
|
+
content: `[${issue.identifier}] ${issue.title}`,
|
|
2171
|
+
metadata: {
|
|
2172
|
+
issueId: issue.id,
|
|
2173
|
+
url: issue.url,
|
|
2174
|
+
team: issue.team?.name,
|
|
2175
|
+
project: issue.project?.name,
|
|
2176
|
+
cycleDays: issue.cycle?.startsAt && issue.completedAt ? Math.round(
|
|
2177
|
+
(new Date(issue.completedAt).getTime() - new Date(issue.cycle.startsAt).getTime()) / (24 * 60 * 60 * 1e3)
|
|
2178
|
+
) : null
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
}
|
|
2182
|
+
if (!completed && !issue.canceledAt) {
|
|
2183
|
+
issuesOpen++;
|
|
2184
|
+
const isInProgress = issue.state?.type === "started";
|
|
2185
|
+
const idleMs = now - updated.getTime();
|
|
2186
|
+
if (isInProgress && idleMs > stallThresholdMs) issuesStalled++;
|
|
2187
|
+
}
|
|
2188
|
+
for (const comment of issue.comments?.nodes ?? []) {
|
|
2189
|
+
const commentedAt = new Date(comment.createdAt);
|
|
2190
|
+
if (commentedAt < since) continue;
|
|
2191
|
+
commentsTotal++;
|
|
2192
|
+
events.push({
|
|
2193
|
+
id: `linear-comment-${comment.id}`,
|
|
2194
|
+
timestamp: comment.createdAt,
|
|
2195
|
+
actor: {
|
|
2196
|
+
id: comment.user?.id ?? "unknown",
|
|
2197
|
+
kind: "human",
|
|
2198
|
+
name: comment.user?.name ?? "unknown"
|
|
2199
|
+
},
|
|
2200
|
+
kind: "issue_comment",
|
|
2201
|
+
content: comment.body.slice(0, 280),
|
|
2202
|
+
metadata: {
|
|
2203
|
+
issueId: issue.id,
|
|
2204
|
+
issueIdentifier: issue.identifier,
|
|
2205
|
+
url: issue.url
|
|
2206
|
+
}
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
let cycleCompletionRate = null;
|
|
2211
|
+
if (rawCycles.length > 0) {
|
|
2212
|
+
const rates = [];
|
|
2213
|
+
for (const cycle of rawCycles) {
|
|
2214
|
+
const committed = cycle.issueCountHistory?.at(0) ?? 0;
|
|
2215
|
+
const completed = cycle.completedIssueCountHistory?.at(-1) ?? 0;
|
|
2216
|
+
if (committed > 0) rates.push(completed / committed);
|
|
2217
|
+
}
|
|
2218
|
+
if (rates.length > 0) {
|
|
2219
|
+
cycleCompletionRate = Math.round(rates.reduce((a, b) => a + b, 0) / rates.length * 100) / 100;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
const topProjects = [...projects.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([name]) => name);
|
|
2223
|
+
const signals = {
|
|
2224
|
+
issuesCreated,
|
|
2225
|
+
issuesCompleted,
|
|
2226
|
+
issuesOpen,
|
|
2227
|
+
issuesStalled,
|
|
2228
|
+
cycleCompletionRate,
|
|
2229
|
+
uniqueAssignees: assignees.size,
|
|
2230
|
+
commentsTotal,
|
|
2231
|
+
topProjects
|
|
2232
|
+
};
|
|
2233
|
+
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
2234
|
+
return { events, signals };
|
|
2235
|
+
}
|
|
2236
|
+
function formatLinearSignalsForPrompt(signals) {
|
|
2237
|
+
if (signals.issuesCreated === 0 && signals.issuesCompleted === 0 && signals.issuesOpen === 0) {
|
|
2238
|
+
return "";
|
|
2239
|
+
}
|
|
2240
|
+
const lines = [
|
|
2241
|
+
"## Linear Activity (planned work vs. shipped outcome)",
|
|
2242
|
+
"",
|
|
2243
|
+
`${signals.issuesCreated} issues created, ${signals.issuesCompleted} completed in window.`,
|
|
2244
|
+
`${signals.issuesOpen} issues still open.`
|
|
2245
|
+
];
|
|
2246
|
+
if (signals.issuesStalled > 0) {
|
|
2247
|
+
lines.push(
|
|
2248
|
+
`${signals.issuesStalled} in-progress issues haven't moved in 14+ days (stalled).`
|
|
2249
|
+
);
|
|
2250
|
+
}
|
|
2251
|
+
if (signals.cycleCompletionRate !== null) {
|
|
2252
|
+
const pct = Math.round(signals.cycleCompletionRate * 100);
|
|
2253
|
+
lines.push(`Cycles ended in window completed ${pct}% of what was committed.`);
|
|
2254
|
+
}
|
|
2255
|
+
if (signals.uniqueAssignees > 0) {
|
|
2256
|
+
lines.push(`${signals.uniqueAssignees} unique assignees active.`);
|
|
2257
|
+
}
|
|
2258
|
+
if (signals.commentsTotal > 0) {
|
|
2259
|
+
lines.push(`${signals.commentsTotal} comments across issues in window.`);
|
|
2260
|
+
}
|
|
2261
|
+
if (signals.topProjects.length > 0) {
|
|
2262
|
+
lines.push(`Most active projects: ${signals.topProjects.join(", ")}.`);
|
|
2263
|
+
}
|
|
2264
|
+
lines.push("");
|
|
2265
|
+
lines.push("Linear is where the team states what it will build.");
|
|
2266
|
+
lines.push("GitHub is where the team reveals what actually got built.");
|
|
2267
|
+
lines.push("Low completion rate + high creation rate = planning faster than shipping.");
|
|
2268
|
+
lines.push("High stalled count = commitments made but not honored.");
|
|
2269
|
+
lines.push("Compare Linear signals against GitHub to find the stated-vs-shipped gap.");
|
|
2270
|
+
return lines.join("\n");
|
|
2271
|
+
}
|
|
2272
|
+
async function fetchLinearGraphQL(apiKey, query, variables) {
|
|
2273
|
+
const res = await fetch("https://api.linear.app/graphql", {
|
|
2274
|
+
method: "POST",
|
|
2275
|
+
headers: {
|
|
2276
|
+
// Linear accepts the raw API key in Authorization with no "Bearer" prefix.
|
|
2277
|
+
Authorization: apiKey,
|
|
2278
|
+
"Content-Type": "application/json"
|
|
2279
|
+
},
|
|
2280
|
+
body: JSON.stringify({ query, variables })
|
|
2281
|
+
});
|
|
2282
|
+
if (!res.ok) {
|
|
2283
|
+
throw new Error(
|
|
2284
|
+
`Linear API error ${res.status}: ${(await res.text()).slice(0, 300)}`
|
|
2285
|
+
);
|
|
2286
|
+
}
|
|
2287
|
+
const json = await res.json();
|
|
2288
|
+
if (json.errors && json.errors.length > 0) {
|
|
2289
|
+
throw new Error(
|
|
2290
|
+
`Linear GraphQL errors: ${json.errors.map((e) => e.message).join("; ")}`
|
|
2291
|
+
);
|
|
2292
|
+
}
|
|
2293
|
+
if (!json.data) {
|
|
2294
|
+
throw new Error("Linear API returned no data");
|
|
2295
|
+
}
|
|
2296
|
+
return json.data;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
// src/radiant/core/vocabulary.ts
|
|
2300
|
+
function extractDeclaredVocabulary(worldmodelContent) {
|
|
2301
|
+
const aligned = extractSection(worldmodelContent, "Aligned Behaviors").map(
|
|
2302
|
+
(b) => parseBehavior(b, "aligned")
|
|
2303
|
+
);
|
|
2304
|
+
const drift = extractSection(worldmodelContent, "Drift Behaviors").map(
|
|
2305
|
+
(b) => parseBehavior(b, "drift")
|
|
2306
|
+
);
|
|
2307
|
+
const allNames = [...aligned, ...drift].map((p) => p.name);
|
|
2308
|
+
return { aligned, drift, allNames };
|
|
2309
|
+
}
|
|
2310
|
+
function extractSection(content, header) {
|
|
2311
|
+
const escaped = header.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2312
|
+
const pattern = new RegExp(
|
|
2313
|
+
`##\\s+${escaped}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)`,
|
|
2314
|
+
"i"
|
|
2315
|
+
);
|
|
2316
|
+
const match = content.match(pattern);
|
|
2317
|
+
if (!match) return [];
|
|
2318
|
+
const body = match[1];
|
|
2319
|
+
const bullets = body.match(/^[-*]\s+.+$/gm);
|
|
2320
|
+
if (!bullets) return [];
|
|
2321
|
+
return bullets.map((b) => b.replace(/^[-*]\s+/, "").trim()).filter((b) => b.length > 0 && !b.startsWith("<!--"));
|
|
2322
|
+
}
|
|
2323
|
+
function parseBehavior(bullet, kind) {
|
|
2324
|
+
const explicit = bullet.match(
|
|
2325
|
+
/^`?([a-z][a-z0-9_]*)`?\s+[—\u2014-]\s+(.+)$/i
|
|
2326
|
+
);
|
|
2327
|
+
if (explicit && isSnakeCase(explicit[1])) {
|
|
2328
|
+
return {
|
|
2329
|
+
name: explicit[1].toLowerCase(),
|
|
2330
|
+
prose: explicit[2].trim(),
|
|
2331
|
+
kind
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
return { name: snakeCaseName(bullet), prose: bullet, kind };
|
|
2335
|
+
}
|
|
2336
|
+
function isSnakeCase(s) {
|
|
2337
|
+
return /^[a-z][a-z0-9_]*$/.test(s);
|
|
2338
|
+
}
|
|
2339
|
+
function snakeCaseName(s) {
|
|
2340
|
+
const base = s.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
2341
|
+
if (base.length <= 60) return base;
|
|
2342
|
+
const truncated = base.slice(0, 60);
|
|
2343
|
+
const lastUnderscore = truncated.lastIndexOf("_");
|
|
2344
|
+
return lastUnderscore > 20 ? truncated.slice(0, lastUnderscore) : truncated;
|
|
2345
|
+
}
|
|
2346
|
+
function matchDeclaredPattern(candidateName, candidateDescription, vocabulary) {
|
|
2347
|
+
const candidateText = `${candidateName.replace(/_/g, " ")} ${candidateDescription}`;
|
|
2348
|
+
const candidateWords = contentWords(candidateText);
|
|
2349
|
+
if (candidateWords.size === 0) return null;
|
|
2350
|
+
let best = null;
|
|
2351
|
+
for (const pattern of [...vocabulary.aligned, ...vocabulary.drift]) {
|
|
2352
|
+
const proseWords = contentWords(pattern.prose);
|
|
2353
|
+
if (proseWords.size === 0) continue;
|
|
2354
|
+
let shared = 0;
|
|
2355
|
+
for (const w of proseWords) {
|
|
2356
|
+
if (candidateWords.has(w)) shared++;
|
|
2357
|
+
}
|
|
2358
|
+
const coverage = shared / proseWords.size;
|
|
2359
|
+
if (shared >= 2 && coverage >= 0.3) {
|
|
2360
|
+
if (!best || coverage > best.score) {
|
|
2361
|
+
best = { pattern, score: coverage };
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
return best?.pattern ?? null;
|
|
2366
|
+
}
|
|
2367
|
+
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
2368
|
+
"about",
|
|
2369
|
+
"after",
|
|
2370
|
+
"against",
|
|
2371
|
+
"among",
|
|
2372
|
+
"around",
|
|
2373
|
+
"because",
|
|
2374
|
+
"been",
|
|
2375
|
+
"before",
|
|
2376
|
+
"being",
|
|
2377
|
+
"between",
|
|
2378
|
+
"both",
|
|
2379
|
+
"could",
|
|
2380
|
+
"does",
|
|
2381
|
+
"doing",
|
|
2382
|
+
"during",
|
|
2383
|
+
"each",
|
|
2384
|
+
"from",
|
|
2385
|
+
"further",
|
|
2386
|
+
"have",
|
|
2387
|
+
"having",
|
|
2388
|
+
"into",
|
|
2389
|
+
"itself",
|
|
2390
|
+
"most",
|
|
2391
|
+
"nor",
|
|
2392
|
+
"only",
|
|
2393
|
+
"other",
|
|
2394
|
+
"over",
|
|
2395
|
+
"same",
|
|
2396
|
+
"should",
|
|
2397
|
+
"some",
|
|
2398
|
+
"such",
|
|
2399
|
+
"than",
|
|
2400
|
+
"that",
|
|
2401
|
+
"their",
|
|
2402
|
+
"them",
|
|
2403
|
+
"then",
|
|
2404
|
+
"there",
|
|
2405
|
+
"these",
|
|
2406
|
+
"they",
|
|
2407
|
+
"this",
|
|
2408
|
+
"those",
|
|
2409
|
+
"through",
|
|
2410
|
+
"under",
|
|
2411
|
+
"until",
|
|
2412
|
+
"very",
|
|
2413
|
+
"were",
|
|
2414
|
+
"what",
|
|
2415
|
+
"when",
|
|
2416
|
+
"where",
|
|
2417
|
+
"which",
|
|
2418
|
+
"while",
|
|
2419
|
+
"will",
|
|
2420
|
+
"with",
|
|
2421
|
+
"without",
|
|
2422
|
+
"would",
|
|
2423
|
+
"your",
|
|
2424
|
+
"yours"
|
|
2425
|
+
]);
|
|
2426
|
+
function contentWords(text) {
|
|
2427
|
+
const words = text.toLowerCase().match(/[a-z][a-z0-9_]+/g) ?? [];
|
|
2428
|
+
return new Set(words.filter((w) => w.length > 3 && !STOPWORDS.has(w)));
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2043
2431
|
// src/radiant/core/patterns.ts
|
|
2044
2432
|
async function interpretPatterns(input) {
|
|
2045
2433
|
const prompt = buildInterpretationPrompt(input);
|
|
2046
2434
|
const raw = await input.ai.complete(prompt, "Analyze the activity and produce the read.");
|
|
2047
|
-
const
|
|
2435
|
+
const canonicalNames = [
|
|
2436
|
+
...input.canonicalPatterns ?? [],
|
|
2437
|
+
...input.declaredVocabulary?.allNames ?? []
|
|
2438
|
+
];
|
|
2439
|
+
const parsed = parseInterpretation(raw, canonicalNames, input.declaredVocabulary);
|
|
2048
2440
|
return {
|
|
2049
2441
|
patterns: parsed.patterns,
|
|
2050
2442
|
meaning: parsed.meaning,
|
|
@@ -2055,8 +2447,10 @@ async function interpretPatterns(input) {
|
|
|
2055
2447
|
function buildInterpretationPrompt(input) {
|
|
2056
2448
|
const signalSummary = formatSignalSummary(input.signals);
|
|
2057
2449
|
const eventSample = formatEventSample(input.events, 30);
|
|
2058
|
-
const canonicalList = (
|
|
2059
|
-
|
|
2450
|
+
const canonicalList = formatDeclaredVocabulary(
|
|
2451
|
+
input.declaredVocabulary,
|
|
2452
|
+
input.canonicalPatterns ?? []
|
|
2453
|
+
);
|
|
2060
2454
|
const compressedWorld = compressWorldmodel(input.worldmodelContent);
|
|
2061
2455
|
const cl = compressLens(input.lens);
|
|
2062
2456
|
const frame = input.lens.primary_frame;
|
|
@@ -2167,6 +2561,44 @@ Only recommend a move when the evidence actually calls for one.
|
|
|
2167
2561
|
Do NOT use these phrases anywhere in your output:
|
|
2168
2562
|
${forbiddenList}`;
|
|
2169
2563
|
}
|
|
2564
|
+
function formatDeclaredVocabulary(vocabulary, extraNames) {
|
|
2565
|
+
const aligned = vocabulary?.aligned ?? [];
|
|
2566
|
+
const drift = vocabulary?.drift ?? [];
|
|
2567
|
+
if (aligned.length === 0 && drift.length === 0 && extraNames.length === 0) {
|
|
2568
|
+
return 'No patterns have been named yet. Everything you observe is new \u2014 mark it type: "candidate".';
|
|
2569
|
+
}
|
|
2570
|
+
const parts = [];
|
|
2571
|
+
parts.push("## Declared vocabulary (use these names when you see matching evidence)");
|
|
2572
|
+
parts.push("");
|
|
2573
|
+
parts.push(
|
|
2574
|
+
'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.'
|
|
2575
|
+
);
|
|
2576
|
+
parts.push("");
|
|
2577
|
+
if (aligned.length > 0) {
|
|
2578
|
+
parts.push("### Aligned behaviors (positive patterns)");
|
|
2579
|
+
for (const p of aligned) {
|
|
2580
|
+
parts.push(`- \`${p.name}\` \u2014 ${p.prose}`);
|
|
2581
|
+
}
|
|
2582
|
+
parts.push("");
|
|
2583
|
+
}
|
|
2584
|
+
if (drift.length > 0) {
|
|
2585
|
+
parts.push("### Drift behaviors (negative patterns)");
|
|
2586
|
+
for (const p of drift) {
|
|
2587
|
+
parts.push(`- \`${p.name}\` \u2014 ${p.prose}`);
|
|
2588
|
+
}
|
|
2589
|
+
parts.push("");
|
|
2590
|
+
}
|
|
2591
|
+
if (extraNames.length > 0) {
|
|
2592
|
+
parts.push(
|
|
2593
|
+
`Additional canonical names (from prior runs or caller): ${extraNames.join(", ")}`
|
|
2594
|
+
);
|
|
2595
|
+
parts.push("");
|
|
2596
|
+
}
|
|
2597
|
+
parts.push(
|
|
2598
|
+
'If you observe something genuinely new that matches NO declared pattern, mark it type: "candidate" with a freshly-invented snake_case name.'
|
|
2599
|
+
);
|
|
2600
|
+
return parts.join("\n");
|
|
2601
|
+
}
|
|
2170
2602
|
function formatSignalSummary(signals) {
|
|
2171
2603
|
const lines = [];
|
|
2172
2604
|
const domains = ["life", "cyber", "joint"];
|
|
@@ -2192,7 +2624,7 @@ function formatEventSample(events, maxEvents) {
|
|
|
2192
2624
|
"${content}"`;
|
|
2193
2625
|
}).join("\n");
|
|
2194
2626
|
}
|
|
2195
|
-
function parseInterpretation(raw, canonicalNames) {
|
|
2627
|
+
function parseInterpretation(raw, canonicalNames, vocabulary) {
|
|
2196
2628
|
let meaning = "";
|
|
2197
2629
|
let move = "";
|
|
2198
2630
|
let patternsArray = [];
|
|
@@ -2222,14 +2654,23 @@ function parseInterpretation(raw, canonicalNames) {
|
|
|
2222
2654
|
const patterns = [];
|
|
2223
2655
|
for (const item of patternsArray) {
|
|
2224
2656
|
if (!isPatternLike(item)) continue;
|
|
2225
|
-
const
|
|
2657
|
+
const rawName = String(item.name ?? "unnamed");
|
|
2658
|
+
const description = String(item.description ?? "");
|
|
2226
2659
|
const ev = item.evidence;
|
|
2227
|
-
|
|
2660
|
+
let name = rawName;
|
|
2661
|
+
let isCanonical = item.type === "canonical" || canonicalSet.has(rawName.toLowerCase());
|
|
2662
|
+
if (!isCanonical && vocabulary) {
|
|
2663
|
+
const matched = matchDeclaredPattern(rawName, description, vocabulary);
|
|
2664
|
+
if (matched) {
|
|
2665
|
+
name = matched.name;
|
|
2666
|
+
isCanonical = true;
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2228
2669
|
patterns.push({
|
|
2229
|
-
name
|
|
2670
|
+
name,
|
|
2230
2671
|
type: isCanonical ? "canonical" : "candidate",
|
|
2231
|
-
declaredAs: isCanonical ?
|
|
2232
|
-
description
|
|
2672
|
+
declaredAs: isCanonical ? name : void 0,
|
|
2673
|
+
description,
|
|
2233
2674
|
evidence: {
|
|
2234
2675
|
signals: Array.isArray(ev?.signals) ? ev.signals.map(String) : [],
|
|
2235
2676
|
events: Array.isArray(ev?.events) ? ev.events.map(String) : [],
|
|
@@ -3119,8 +3560,26 @@ function isExternalScope(scope) {
|
|
|
3119
3560
|
];
|
|
3120
3561
|
return !internalPatterns.some((p) => p.test(scope));
|
|
3121
3562
|
}
|
|
3122
|
-
var MAX_INPUT_LENGTH = 1e5;
|
|
3123
3563
|
function evaluateGuard(event, world, options = {}) {
|
|
3564
|
+
const verdict = evaluateGuardCore(event, world, options);
|
|
3565
|
+
return options.mode === "observe" ? toShadowVerdict(verdict) : verdict;
|
|
3566
|
+
}
|
|
3567
|
+
function toShadowVerdict(verdict) {
|
|
3568
|
+
if (verdict.status === "ALLOW") return verdict;
|
|
3569
|
+
return {
|
|
3570
|
+
...verdict,
|
|
3571
|
+
status: "ALLOW",
|
|
3572
|
+
shadowStatus: verdict.status,
|
|
3573
|
+
shadowReason: verdict.reason,
|
|
3574
|
+
// Preserve the original reason as shadowReason and wipe the
|
|
3575
|
+
// top-level reason so callers that display `reason` for BLOCK/PAUSE
|
|
3576
|
+
// don't accidentally surface an enforcement message.
|
|
3577
|
+
reason: void 0,
|
|
3578
|
+
warning: verdict.reason ? `Observe mode: would have ${verdict.status.toLowerCase()} \u2014 ${verdict.reason}` : `Observe mode: would have ${verdict.status.toLowerCase()}`
|
|
3579
|
+
};
|
|
3580
|
+
}
|
|
3581
|
+
var MAX_INPUT_LENGTH = 1e5;
|
|
3582
|
+
function evaluateGuardCore(event, world, options = {}) {
|
|
3124
3583
|
const startTime = performance.now();
|
|
3125
3584
|
const level = options.level ?? "standard";
|
|
3126
3585
|
const includeTrace = options.trace ?? false;
|
|
@@ -4010,6 +4469,7 @@ async function auditGovernance(events, worldPath) {
|
|
|
4010
4469
|
return emptyAudit(events.length, "Could not load compiled worldmodel for governance audit.");
|
|
4011
4470
|
}
|
|
4012
4471
|
const verdicts = [];
|
|
4472
|
+
const crossings = [];
|
|
4013
4473
|
for (const ce of events) {
|
|
4014
4474
|
const intent = ce.event.content?.slice(0, 500) || ce.event.kind || "activity";
|
|
4015
4475
|
const scope = ce.event.metadata?.scope || void 0;
|
|
@@ -4020,16 +4480,32 @@ async function auditGovernance(events, worldPath) {
|
|
|
4020
4480
|
scope,
|
|
4021
4481
|
actionCategory: mapKindToCategory(ce.event.kind)
|
|
4022
4482
|
},
|
|
4023
|
-
world
|
|
4483
|
+
world,
|
|
4484
|
+
{ mode: "observe" }
|
|
4024
4485
|
);
|
|
4486
|
+
const shadow = result.shadowStatus ?? "ALLOW";
|
|
4025
4487
|
verdicts.push({
|
|
4026
4488
|
eventId: ce.event.id,
|
|
4027
4489
|
domain: ce.domain,
|
|
4028
|
-
status:
|
|
4029
|
-
reason: result.
|
|
4490
|
+
status: shadow,
|
|
4491
|
+
reason: result.shadowReason,
|
|
4030
4492
|
ruleId: result.ruleId,
|
|
4031
4493
|
warning: result.warning
|
|
4032
4494
|
});
|
|
4495
|
+
if (shadow !== "ALLOW") {
|
|
4496
|
+
crossings.push({
|
|
4497
|
+
eventId: ce.event.id,
|
|
4498
|
+
timestamp: ce.event.timestamp,
|
|
4499
|
+
kind: ce.event.kind,
|
|
4500
|
+
actorId: ce.event.actor.id,
|
|
4501
|
+
shadowStatus: shadow,
|
|
4502
|
+
shadowReason: result.shadowReason,
|
|
4503
|
+
ruleId: result.ruleId,
|
|
4504
|
+
excerpt: intent.length > 280 ? intent.slice(0, 279) + "\u2026" : intent,
|
|
4505
|
+
wouldHaveBlocked: true,
|
|
4506
|
+
verdict: result
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4033
4509
|
} catch {
|
|
4034
4510
|
verdicts.push({
|
|
4035
4511
|
eventId: ce.event.id,
|
|
@@ -4048,6 +4524,7 @@ async function auditGovernance(events, worldPath) {
|
|
|
4048
4524
|
human,
|
|
4049
4525
|
cyber,
|
|
4050
4526
|
joint,
|
|
4527
|
+
crossings,
|
|
4051
4528
|
summary
|
|
4052
4529
|
};
|
|
4053
4530
|
}
|
|
@@ -4103,6 +4580,7 @@ function emptyAudit(total, reason) {
|
|
|
4103
4580
|
human: { allow: 0, modify: 0, block: 0, details: [] },
|
|
4104
4581
|
cyber: { allow: 0, modify: 0, block: 0, details: [] },
|
|
4105
4582
|
joint: { allow: 0, modify: 0, block: 0, details: [] },
|
|
4583
|
+
crossings: [],
|
|
4106
4584
|
summary: reason
|
|
4107
4585
|
};
|
|
4108
4586
|
}
|
|
@@ -4408,10 +4886,24 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
|
4408
4886
|
} catch {
|
|
4409
4887
|
}
|
|
4410
4888
|
}
|
|
4889
|
+
const linearKey = process.env.LINEAR_API_KEY;
|
|
4890
|
+
if (linearKey) {
|
|
4891
|
+
try {
|
|
4892
|
+
const linear = await fetchLinearActivity(linearKey, { windowDays });
|
|
4893
|
+
events.push(...linear.events);
|
|
4894
|
+
adapterSignals += "\n\n" + formatLinearSignalsForPrompt(linear.signals);
|
|
4895
|
+
activeAdapters.push("linear");
|
|
4896
|
+
} catch {
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4411
4899
|
events.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
4900
|
+
if (input.personalUser) {
|
|
4901
|
+
events = filterEventsByUser(events, input.personalUser);
|
|
4902
|
+
}
|
|
4412
4903
|
const classified = classifyEvents(events);
|
|
4413
4904
|
const signals = extractSignals(classified);
|
|
4414
4905
|
const scores = computeScores(signals, input.worldmodelContent !== "");
|
|
4906
|
+
const declaredVocabulary = extractDeclaredVocabulary(worldmodelContent);
|
|
4415
4907
|
const { patterns, meaning, move } = await interpretPatterns({
|
|
4416
4908
|
signals,
|
|
4417
4909
|
events: classified,
|
|
@@ -4419,6 +4911,7 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
|
4419
4911
|
lens,
|
|
4420
4912
|
ai: input.ai,
|
|
4421
4913
|
canonicalPatterns: input.canonicalPatterns,
|
|
4914
|
+
declaredVocabulary,
|
|
4422
4915
|
statedIntent: [statedIntent, adapterSignals, priorReadContext].filter(Boolean).join("\n\n") || void 0
|
|
4423
4916
|
});
|
|
4424
4917
|
const rewrittenPatterns = patterns.map((p) => lens.rewrite(p));
|
|
@@ -4470,9 +4963,14 @@ Compare stated intent against actual GitHub activity. Gaps = drift.`;
|
|
|
4470
4963
|
scores,
|
|
4471
4964
|
eventCount: events.length,
|
|
4472
4965
|
activeAdapters,
|
|
4473
|
-
worldStack
|
|
4966
|
+
worldStack,
|
|
4967
|
+
governance
|
|
4474
4968
|
};
|
|
4475
4969
|
}
|
|
4970
|
+
function filterEventsByUser(events, username) {
|
|
4971
|
+
const target = username.toLowerCase();
|
|
4972
|
+
return events.filter((e) => e.actor.id.toLowerCase() === target);
|
|
4973
|
+
}
|
|
4476
4974
|
function computeScores(signals, worldmodelLoaded) {
|
|
4477
4975
|
const gate = DEFAULT_EVIDENCE_GATE;
|
|
4478
4976
|
const lifeSignals = signals.filter((s) => s.domain === "life");
|
|
@@ -4546,15 +5044,19 @@ var RADIANT_PACKAGE_VERSION = "0.0.0";
|
|
|
4546
5044
|
detectOrgExtendsSpec,
|
|
4547
5045
|
discoverWorlds,
|
|
4548
5046
|
emergent,
|
|
5047
|
+
extractDeclaredVocabulary,
|
|
4549
5048
|
extractSignals,
|
|
4550
5049
|
fetchDiscordActivity,
|
|
4551
5050
|
fetchGitHubActivity,
|
|
4552
5051
|
fetchGitHubOrgActivity,
|
|
5052
|
+
fetchLinearActivity,
|
|
4553
5053
|
fetchNotionActivity,
|
|
4554
5054
|
fetchSlackActivity,
|
|
5055
|
+
filterEventsByUser,
|
|
4555
5056
|
formatActiveWorlds,
|
|
4556
5057
|
formatDiscordSignalsForPrompt,
|
|
4557
5058
|
formatExocortexForPrompt,
|
|
5059
|
+
formatLinearSignalsForPrompt,
|
|
4558
5060
|
formatNotionSignalsForPrompt,
|
|
4559
5061
|
formatPriorReadsForPrompt,
|
|
4560
5062
|
formatScope,
|
|
@@ -4570,6 +5072,7 @@ var RADIANT_PACKAGE_VERSION = "0.0.0";
|
|
|
4570
5072
|
listLenses,
|
|
4571
5073
|
loadExtendsConfig,
|
|
4572
5074
|
loadPriorReads,
|
|
5075
|
+
matchDeclaredPattern,
|
|
4573
5076
|
parseExtendsSpec,
|
|
4574
5077
|
parseRemoteUrl,
|
|
4575
5078
|
parseRepoScope,
|