hebbian 0.7.1 → 0.8.1
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/dist/bin/hebbian.js +506 -112
- package/dist/bin/hebbian.js.map +1 -1
- package/dist/candidates.d.ts +8 -0
- package/dist/candidates.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/cron.d.ts +24 -0
- package/dist/cron.d.ts.map +1 -0
- package/dist/digest.d.ts +13 -1
- package/dist/digest.d.ts.map +1 -1
- package/dist/evolve.d.ts.map +1 -1
- package/dist/feedback.d.ts +23 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +427 -93
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/scanner.d.ts +6 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -73,6 +73,8 @@ function resolveSharedBrain(brainRoot) {
|
|
|
73
73
|
}
|
|
74
74
|
var AGENTS_DIR = "agents";
|
|
75
75
|
var SHARED_DIR = "shared";
|
|
76
|
+
var SKILLS_DIR = "skills";
|
|
77
|
+
var PROPAGATION_EPISODE_TYPES = ["tool-failure", "retry-pattern"];
|
|
76
78
|
|
|
77
79
|
// src/scanner.ts
|
|
78
80
|
import { readdirSync, statSync, readFileSync, existsSync as existsSync2 } from "fs";
|
|
@@ -198,6 +200,11 @@ function walkRegion(dir, regionRoot, depth) {
|
|
|
198
200
|
}
|
|
199
201
|
return neurons;
|
|
200
202
|
}
|
|
203
|
+
function scanSkills(brainRoot) {
|
|
204
|
+
const skillsPath = join(brainRoot, SKILLS_DIR);
|
|
205
|
+
if (!existsSync2(skillsPath)) return [];
|
|
206
|
+
return walkRegion(skillsPath, skillsPath, 0);
|
|
207
|
+
}
|
|
201
208
|
function readAxons(regionPath) {
|
|
202
209
|
const axonPath = join(regionPath, ".axon");
|
|
203
210
|
if (!existsSync2(axonPath)) return [];
|
|
@@ -413,8 +420,8 @@ function growNeuron(brainRoot, neuronPath) {
|
|
|
413
420
|
}
|
|
414
421
|
const parts = neuronPath.split("/");
|
|
415
422
|
const regionName = parts[0];
|
|
416
|
-
if (!REGIONS.includes(regionName)) {
|
|
417
|
-
throw new Error(`Invalid region: ${regionName}. Valid: ${REGIONS.join(", ")}`);
|
|
423
|
+
if (regionName !== SKILLS_DIR && !REGIONS.includes(regionName)) {
|
|
424
|
+
throw new Error(`Invalid region: ${regionName}. Valid: ${REGIONS.join(", ")}, ${SKILLS_DIR}`);
|
|
418
425
|
}
|
|
419
426
|
const leafName = parts[parts.length - 1];
|
|
420
427
|
const newPrefix = leafName.match(/^(NO|DO|MUST|WARN)_/)?.[1] || "";
|
|
@@ -952,6 +959,12 @@ ${template.description}
|
|
|
952
959
|
}
|
|
953
960
|
}
|
|
954
961
|
mkdirSync4(join10(brainPath, "_agents", "global_inbox"), { recursive: true });
|
|
962
|
+
mkdirSync4(join10(brainPath, "skills"), { recursive: true });
|
|
963
|
+
writeFileSync7(
|
|
964
|
+
join10(brainPath, "skills", "_rules.md"),
|
|
965
|
+
"# Skills Library\n\nExecutable patterns learned through experience.\nNot part of the subsumption cascade \u2014 retrieval only.\n",
|
|
966
|
+
"utf8"
|
|
967
|
+
);
|
|
955
968
|
autoGitignore(brainPath);
|
|
956
969
|
console.log(`\u{1F9E0} Brain initialized at ${brainPath}`);
|
|
957
970
|
console.log(` 7 regions created: ${REGIONS.join(", ")}`);
|
|
@@ -993,8 +1006,73 @@ import { readFileSync as readFileSync5, writeFileSync as writeFileSync9, existsS
|
|
|
993
1006
|
import { join as join13 } from "path";
|
|
994
1007
|
|
|
995
1008
|
// src/candidates.ts
|
|
996
|
-
import { existsSync as
|
|
997
|
-
import { join as
|
|
1009
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readdirSync as readdirSync8, renameSync as renameSync3, rmSync, statSync as statSync3 } from "fs";
|
|
1010
|
+
import { join as join12, dirname as dirname3, relative as relative3 } from "path";
|
|
1011
|
+
|
|
1012
|
+
// src/episode.ts
|
|
1013
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5, existsSync as existsSync10 } from "fs";
|
|
1014
|
+
import { join as join11 } from "path";
|
|
1015
|
+
var MAX_EPISODES = 100;
|
|
1016
|
+
var SESSION_LOG_DIR = "hippocampus/session_log";
|
|
1017
|
+
function logEpisode(brainRoot, type, path, detail, extra) {
|
|
1018
|
+
const logDir = join11(brainRoot, SESSION_LOG_DIR);
|
|
1019
|
+
if (!existsSync10(logDir)) {
|
|
1020
|
+
mkdirSync5(logDir, { recursive: true });
|
|
1021
|
+
}
|
|
1022
|
+
const nextSlot = getNextSlot(logDir);
|
|
1023
|
+
const episode = {
|
|
1024
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1025
|
+
type,
|
|
1026
|
+
path,
|
|
1027
|
+
detail,
|
|
1028
|
+
...extra?.outcome ? { outcome: extra.outcome } : {},
|
|
1029
|
+
...extra?.neurons ? { neurons: extra.neurons } : {}
|
|
1030
|
+
};
|
|
1031
|
+
writeFileSync8(
|
|
1032
|
+
join11(logDir, `memory${nextSlot}.neuron`),
|
|
1033
|
+
JSON.stringify(episode),
|
|
1034
|
+
"utf8"
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
function readEpisodes(brainRoot) {
|
|
1038
|
+
const logDir = join11(brainRoot, SESSION_LOG_DIR);
|
|
1039
|
+
if (!existsSync10(logDir)) return [];
|
|
1040
|
+
const episodes = [];
|
|
1041
|
+
let entries;
|
|
1042
|
+
try {
|
|
1043
|
+
entries = readdirSync7(logDir);
|
|
1044
|
+
} catch {
|
|
1045
|
+
return [];
|
|
1046
|
+
}
|
|
1047
|
+
for (const entry of entries) {
|
|
1048
|
+
if (!entry.startsWith("memory") || !entry.endsWith(".neuron")) continue;
|
|
1049
|
+
try {
|
|
1050
|
+
const content = readFileSync4(join11(logDir, entry), "utf8");
|
|
1051
|
+
if (content.trim()) {
|
|
1052
|
+
episodes.push(JSON.parse(content));
|
|
1053
|
+
}
|
|
1054
|
+
} catch {
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
episodes.sort((a, b) => a.ts.localeCompare(b.ts));
|
|
1058
|
+
return episodes;
|
|
1059
|
+
}
|
|
1060
|
+
function getNextSlot(logDir) {
|
|
1061
|
+
let maxSlot = 0;
|
|
1062
|
+
try {
|
|
1063
|
+
for (const entry of readdirSync7(logDir)) {
|
|
1064
|
+
if (entry.startsWith("memory") && entry.endsWith(".neuron")) {
|
|
1065
|
+
const n = parseInt(entry.replace("memory", "").replace(".neuron", ""), 10);
|
|
1066
|
+
if (!isNaN(n) && n > maxSlot) maxSlot = n;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
} catch {
|
|
1070
|
+
}
|
|
1071
|
+
const next = maxSlot + 1;
|
|
1072
|
+
return next > MAX_EPISODES ? maxSlot % MAX_EPISODES + 1 : next;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// src/candidates.ts
|
|
998
1076
|
var CANDIDATE_THRESHOLD = 3;
|
|
999
1077
|
var CANDIDATE_DECAY_DAYS = 14;
|
|
1000
1078
|
var CANDIDATE_SEGMENT = "_candidates";
|
|
@@ -1011,20 +1089,21 @@ function growCandidate(brainRoot, neuronPath) {
|
|
|
1011
1089
|
const result = growNeuron(brainRoot, candidatePath);
|
|
1012
1090
|
if (result.counter >= CANDIDATE_THRESHOLD) {
|
|
1013
1091
|
const ok = moveCandidate(brainRoot, candidatePath, neuronPath);
|
|
1092
|
+
if (ok) propagateToShared(brainRoot, neuronPath);
|
|
1014
1093
|
return { ...result, path: ok ? neuronPath : result.path, promoted: ok };
|
|
1015
1094
|
}
|
|
1016
1095
|
console.log(` \u{1F331} candidate (${result.counter}/${CANDIDATE_THRESHOLD}): ${candidatePath}`);
|
|
1017
1096
|
return { ...result, promoted: false };
|
|
1018
1097
|
}
|
|
1019
1098
|
function moveCandidate(brainRoot, candidatePath, targetPath) {
|
|
1020
|
-
const src =
|
|
1021
|
-
if (!
|
|
1022
|
-
const dst =
|
|
1023
|
-
if (
|
|
1099
|
+
const src = join12(brainRoot, candidatePath);
|
|
1100
|
+
if (!existsSync11(src)) return false;
|
|
1101
|
+
const dst = join12(brainRoot, targetPath);
|
|
1102
|
+
if (existsSync11(dst)) {
|
|
1024
1103
|
fireNeuron(brainRoot, targetPath);
|
|
1025
1104
|
rmSync(src, { recursive: true, force: true });
|
|
1026
1105
|
} else {
|
|
1027
|
-
|
|
1106
|
+
mkdirSync6(dirname3(dst), { recursive: true });
|
|
1028
1107
|
renameSync3(src, dst);
|
|
1029
1108
|
}
|
|
1030
1109
|
console.log(`\u{1F393} promoted: ${candidatePath} \u2192 ${targetPath}`);
|
|
@@ -1036,15 +1115,16 @@ function promoteCandidates(brainRoot) {
|
|
|
1036
1115
|
const decayMs = CANDIDATE_DECAY_DAYS * 24 * 60 * 60 * 1e3;
|
|
1037
1116
|
const now = Date.now();
|
|
1038
1117
|
for (const region of REGIONS) {
|
|
1039
|
-
const candidateRoot =
|
|
1118
|
+
const candidateRoot = join12(brainRoot, region, CANDIDATE_SEGMENT);
|
|
1040
1119
|
walkNeuronDirs(candidateRoot, (neuronDir) => {
|
|
1041
|
-
const rel = relative3(
|
|
1120
|
+
const rel = relative3(join12(brainRoot, region), neuronDir);
|
|
1042
1121
|
const candidatePath = `${region}/${rel}`;
|
|
1043
1122
|
const targetPath = fromCandidatePath(candidatePath);
|
|
1044
1123
|
const counter = readCounter(neuronDir);
|
|
1045
1124
|
const mtime = statSync3(neuronDir).mtimeMs;
|
|
1046
1125
|
if (counter >= CANDIDATE_THRESHOLD) {
|
|
1047
1126
|
moveCandidate(brainRoot, candidatePath, targetPath);
|
|
1127
|
+
propagateToShared(brainRoot, targetPath);
|
|
1048
1128
|
promoted.push(targetPath);
|
|
1049
1129
|
} else if (now - mtime > decayMs) {
|
|
1050
1130
|
rmSync(neuronDir, { recursive: true, force: true });
|
|
@@ -1059,9 +1139,9 @@ function listCandidates(brainRoot) {
|
|
|
1059
1139
|
const results = [];
|
|
1060
1140
|
const now = Date.now();
|
|
1061
1141
|
for (const region of REGIONS) {
|
|
1062
|
-
const candidateRoot =
|
|
1142
|
+
const candidateRoot = join12(brainRoot, region, CANDIDATE_SEGMENT);
|
|
1063
1143
|
walkNeuronDirs(candidateRoot, (neuronDir) => {
|
|
1064
|
-
const rel = relative3(
|
|
1144
|
+
const rel = relative3(join12(brainRoot, region), neuronDir);
|
|
1065
1145
|
const candidatePath = `${region}/${rel}`;
|
|
1066
1146
|
const targetPath = fromCandidatePath(candidatePath);
|
|
1067
1147
|
const counter = readCounter(neuronDir);
|
|
@@ -1073,9 +1153,9 @@ function listCandidates(brainRoot) {
|
|
|
1073
1153
|
return results;
|
|
1074
1154
|
}
|
|
1075
1155
|
function walkNeuronDirs(dir, cb) {
|
|
1076
|
-
if (!
|
|
1156
|
+
if (!existsSync11(dir)) return;
|
|
1077
1157
|
try {
|
|
1078
|
-
const entries =
|
|
1158
|
+
const entries = readdirSync8(dir, { withFileTypes: true });
|
|
1079
1159
|
const hasNeuron = entries.some((e) => e.isFile() && e.name.endsWith(".neuron"));
|
|
1080
1160
|
if (hasNeuron) {
|
|
1081
1161
|
cb(dir);
|
|
@@ -1083,7 +1163,7 @@ function walkNeuronDirs(dir, cb) {
|
|
|
1083
1163
|
}
|
|
1084
1164
|
for (const entry of entries) {
|
|
1085
1165
|
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
1086
|
-
walkNeuronDirs(
|
|
1166
|
+
walkNeuronDirs(join12(dir, entry.name), cb);
|
|
1087
1167
|
}
|
|
1088
1168
|
}
|
|
1089
1169
|
} catch {
|
|
@@ -1091,75 +1171,32 @@ function walkNeuronDirs(dir, cb) {
|
|
|
1091
1171
|
}
|
|
1092
1172
|
function readCounter(dir) {
|
|
1093
1173
|
try {
|
|
1094
|
-
const files =
|
|
1174
|
+
const files = readdirSync8(dir).filter((f) => /^\d+\.neuron$/.test(f));
|
|
1095
1175
|
if (files.length === 0) return 0;
|
|
1096
1176
|
return Math.max(...files.map((f) => parseInt(f, 10)));
|
|
1097
1177
|
} catch {
|
|
1098
1178
|
return 0;
|
|
1099
1179
|
}
|
|
1100
1180
|
}
|
|
1101
|
-
|
|
1102
|
-
// src/episode.ts
|
|
1103
|
-
import { readdirSync as readdirSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, existsSync as existsSync11 } from "fs";
|
|
1104
|
-
import { join as join12 } from "path";
|
|
1105
|
-
var MAX_EPISODES = 100;
|
|
1106
|
-
var SESSION_LOG_DIR = "hippocampus/session_log";
|
|
1107
|
-
function logEpisode(brainRoot, type, path, detail, extra) {
|
|
1108
|
-
const logDir = join12(brainRoot, SESSION_LOG_DIR);
|
|
1109
|
-
if (!existsSync11(logDir)) {
|
|
1110
|
-
mkdirSync6(logDir, { recursive: true });
|
|
1111
|
-
}
|
|
1112
|
-
const nextSlot = getNextSlot(logDir);
|
|
1113
|
-
const episode = {
|
|
1114
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1115
|
-
type,
|
|
1116
|
-
path,
|
|
1117
|
-
detail,
|
|
1118
|
-
...extra?.outcome ? { outcome: extra.outcome } : {},
|
|
1119
|
-
...extra?.neurons ? { neurons: extra.neurons } : {}
|
|
1120
|
-
};
|
|
1121
|
-
writeFileSync8(
|
|
1122
|
-
join12(logDir, `memory${nextSlot}.neuron`),
|
|
1123
|
-
JSON.stringify(episode),
|
|
1124
|
-
"utf8"
|
|
1125
|
-
);
|
|
1126
|
-
}
|
|
1127
|
-
function readEpisodes(brainRoot) {
|
|
1128
|
-
const logDir = join12(brainRoot, SESSION_LOG_DIR);
|
|
1129
|
-
if (!existsSync11(logDir)) return [];
|
|
1130
|
-
const episodes = [];
|
|
1131
|
-
let entries;
|
|
1181
|
+
function propagateToShared(brainRoot, targetPath) {
|
|
1132
1182
|
try {
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
episodes.sort((a, b) => a.ts.localeCompare(b.ts));
|
|
1148
|
-
return episodes;
|
|
1149
|
-
}
|
|
1150
|
-
function getNextSlot(logDir) {
|
|
1151
|
-
let maxSlot = 0;
|
|
1152
|
-
try {
|
|
1153
|
-
for (const entry of readdirSync8(logDir)) {
|
|
1154
|
-
if (entry.startsWith("memory") && entry.endsWith(".neuron")) {
|
|
1155
|
-
const n = parseInt(entry.replace("memory", "").replace(".neuron", ""), 10);
|
|
1156
|
-
if (!isNaN(n) && n > maxSlot) maxSlot = n;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1183
|
+
const agentsIdx = brainRoot.indexOf("/agents/");
|
|
1184
|
+
if (agentsIdx === -1) return false;
|
|
1185
|
+
const multiBrainRoot = brainRoot.slice(0, agentsIdx);
|
|
1186
|
+
const sharedRoot = join12(multiBrainRoot, "shared");
|
|
1187
|
+
if (!existsSync11(sharedRoot)) return false;
|
|
1188
|
+
const episodes = readEpisodes(brainRoot);
|
|
1189
|
+
const neuronName = targetPath.split("/").pop() || "";
|
|
1190
|
+
const hasRelevantEpisode = episodes.some(
|
|
1191
|
+
(ep) => PROPAGATION_EPISODE_TYPES.includes(ep.type) && (ep.path.includes(neuronName) || ep.detail.includes(neuronName))
|
|
1192
|
+
);
|
|
1193
|
+
if (!hasRelevantEpisode) return false;
|
|
1194
|
+
growNeuron(sharedRoot, targetPath);
|
|
1195
|
+
console.log(` \u{1F4E1} propagated to shared: ${targetPath}`);
|
|
1196
|
+
return true;
|
|
1159
1197
|
} catch {
|
|
1198
|
+
return false;
|
|
1160
1199
|
}
|
|
1161
|
-
const next = maxSlot + 1;
|
|
1162
|
-
return next > MAX_EPISODES ? maxSlot % MAX_EPISODES + 1 : next;
|
|
1163
1200
|
}
|
|
1164
1201
|
|
|
1165
1202
|
// src/inbox.ts
|
|
@@ -1777,12 +1814,21 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
1777
1814
|
const resolvedSessionId = sessionId || basename(transcriptPath, ".jsonl");
|
|
1778
1815
|
const logDir = join15(brainRoot, DIGEST_LOG_DIR);
|
|
1779
1816
|
const logPath = join15(logDir, `${resolvedSessionId}.jsonl`);
|
|
1780
|
-
|
|
1817
|
+
const content = readFileSync7(transcriptPath, "utf8");
|
|
1818
|
+
const allLines = content.split("\n").filter(Boolean);
|
|
1819
|
+
const totalLines = allLines.length;
|
|
1820
|
+
const meta = readAuditMeta(logPath);
|
|
1821
|
+
if (existsSync14(logPath) && !meta) {
|
|
1781
1822
|
console.log(`\u23ED already digested session ${resolvedSessionId}, skip`);
|
|
1782
1823
|
return { corrections: 0, skipped: 0, toolFailures: 0, transcriptPath, sessionId: resolvedSessionId };
|
|
1783
1824
|
}
|
|
1784
|
-
const
|
|
1785
|
-
|
|
1825
|
+
const skipLines = meta ? meta.lineCount : 0;
|
|
1826
|
+
if (skipLines >= totalLines) {
|
|
1827
|
+
return { corrections: 0, skipped: 0, toolFailures: 0, transcriptPath, sessionId: resolvedSessionId };
|
|
1828
|
+
}
|
|
1829
|
+
const newLines = allLines.slice(skipLines);
|
|
1830
|
+
const messages = parseTranscriptFromLines(newLines);
|
|
1831
|
+
const toolFailures = parseToolResultsFromLines(newLines);
|
|
1786
1832
|
for (const failure of toolFailures) {
|
|
1787
1833
|
logEpisode(brainRoot, "tool-failure", failure.toolName, failure.errorText);
|
|
1788
1834
|
}
|
|
@@ -1797,11 +1843,11 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
1797
1843
|
const corrections = extractCorrections(messages);
|
|
1798
1844
|
if (corrections.length === 0 && toolFailures.length === 0) {
|
|
1799
1845
|
console.log(`\u{1F4DD} digest: no corrections found in session ${resolvedSessionId}`);
|
|
1800
|
-
writeAuditLog(brainRoot, resolvedSessionId, []);
|
|
1846
|
+
writeAuditLog(brainRoot, resolvedSessionId, [], totalLines);
|
|
1801
1847
|
return { corrections: 0, skipped: messages.length, toolFailures: toolFailures.length, transcriptPath, sessionId: resolvedSessionId };
|
|
1802
1848
|
}
|
|
1803
1849
|
if (corrections.length === 0) {
|
|
1804
|
-
writeAuditLog(brainRoot, resolvedSessionId, []);
|
|
1850
|
+
writeAuditLog(brainRoot, resolvedSessionId, [], totalLines);
|
|
1805
1851
|
return { corrections: 0, skipped: messages.length, toolFailures: toolFailures.length, transcriptPath, sessionId: resolvedSessionId };
|
|
1806
1852
|
}
|
|
1807
1853
|
let applied = 0;
|
|
@@ -1817,7 +1863,7 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
1817
1863
|
auditEntries.push({ correction, applied: false });
|
|
1818
1864
|
}
|
|
1819
1865
|
}
|
|
1820
|
-
writeAuditLog(brainRoot, resolvedSessionId, auditEntries);
|
|
1866
|
+
writeAuditLog(brainRoot, resolvedSessionId, auditEntries, totalLines);
|
|
1821
1867
|
console.log(`\u{1F4DD} digest: ${applied} correction(s) from session ${resolvedSessionId}`);
|
|
1822
1868
|
return {
|
|
1823
1869
|
corrections: applied,
|
|
@@ -1827,9 +1873,7 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
1827
1873
|
sessionId: resolvedSessionId
|
|
1828
1874
|
};
|
|
1829
1875
|
}
|
|
1830
|
-
function
|
|
1831
|
-
const content = readFileSync7(transcriptPath, "utf8");
|
|
1832
|
-
const lines = content.split("\n").filter(Boolean);
|
|
1876
|
+
function parseTranscriptFromLines(lines) {
|
|
1833
1877
|
const messages = [];
|
|
1834
1878
|
for (const line of lines) {
|
|
1835
1879
|
let entry;
|
|
@@ -1855,9 +1899,19 @@ function extractText(content) {
|
|
|
1855
1899
|
return null;
|
|
1856
1900
|
}
|
|
1857
1901
|
var MAX_FAILURES_PER_SESSION = 20;
|
|
1902
|
+
var SOFT_ERROR_PATTERNS = [
|
|
1903
|
+
/(?:^|\n)\S*(?:\(\w+\):\d+: )?command not found:/m,
|
|
1904
|
+
// shell: command not found
|
|
1905
|
+
/(?:^|\n)npm error\b/m,
|
|
1906
|
+
// npm error (not npm warn)
|
|
1907
|
+
/(?:^|\n)fatal: /m
|
|
1908
|
+
// git fatal
|
|
1909
|
+
];
|
|
1858
1910
|
function parseToolResults(transcriptPath) {
|
|
1859
1911
|
const content = readFileSync7(transcriptPath, "utf8");
|
|
1860
|
-
|
|
1912
|
+
return parseToolResultsFromLines(content.split("\n").filter(Boolean));
|
|
1913
|
+
}
|
|
1914
|
+
function parseToolResultsFromLines(lines) {
|
|
1861
1915
|
const failures = [];
|
|
1862
1916
|
for (const line of lines) {
|
|
1863
1917
|
if (failures.length >= MAX_FAILURES_PER_SESSION) break;
|
|
@@ -1871,9 +1925,13 @@ function parseToolResults(transcriptPath) {
|
|
|
1871
1925
|
if (!entry.message || !Array.isArray(entry.message.content)) continue;
|
|
1872
1926
|
for (const block of entry.message.content) {
|
|
1873
1927
|
if (block.type !== "tool_result") continue;
|
|
1874
|
-
if (
|
|
1875
|
-
|
|
1876
|
-
|
|
1928
|
+
if (block.is_error) {
|
|
1929
|
+
const failure = detectToolFailure(block, entry.toolUseResult);
|
|
1930
|
+
if (failure) failures.push(failure);
|
|
1931
|
+
} else {
|
|
1932
|
+
const failure = detectSoftFailure(block, entry.toolUseResult);
|
|
1933
|
+
if (failure) failures.push(failure);
|
|
1934
|
+
}
|
|
1877
1935
|
}
|
|
1878
1936
|
}
|
|
1879
1937
|
return failures;
|
|
@@ -1912,6 +1970,30 @@ function detectToolFailure(block, toolUseResult) {
|
|
|
1912
1970
|
const toolName = firstLine.trim().slice(0, 80);
|
|
1913
1971
|
return { toolName, exitCode, errorText: errorText.slice(0, 500) };
|
|
1914
1972
|
}
|
|
1973
|
+
function detectSoftFailure(block, toolUseResult) {
|
|
1974
|
+
let text = "";
|
|
1975
|
+
if (typeof block.content === "string") {
|
|
1976
|
+
text = block.content;
|
|
1977
|
+
} else if (Array.isArray(block.content)) {
|
|
1978
|
+
text = block.content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("\n");
|
|
1979
|
+
}
|
|
1980
|
+
if (toolUseResult && typeof toolUseResult === "object") {
|
|
1981
|
+
if (toolUseResult.stderr) text += "\n" + toolUseResult.stderr;
|
|
1982
|
+
}
|
|
1983
|
+
if (!text) return null;
|
|
1984
|
+
for (const pattern of SOFT_ERROR_PATTERNS) {
|
|
1985
|
+
const match = text.match(pattern);
|
|
1986
|
+
if (match) {
|
|
1987
|
+
const matchedLine = text.split("\n").find((l) => pattern.test(l)) || "unknown";
|
|
1988
|
+
return {
|
|
1989
|
+
toolName: `[soft] ${matchedLine.trim().slice(0, 70)}`,
|
|
1990
|
+
exitCode: 0,
|
|
1991
|
+
errorText: text.slice(0, 500)
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
return null;
|
|
1996
|
+
}
|
|
1915
1997
|
function extractCorrections(messages) {
|
|
1916
1998
|
const corrections = [];
|
|
1917
1999
|
for (const text of messages) {
|
|
@@ -2086,13 +2168,28 @@ function extractKeywords(text) {
|
|
|
2086
2168
|
]);
|
|
2087
2169
|
return text.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[^a-zA-Z0-9\u3000-\u9FFF\uAC00-\uD7AF]+/g, " ").toLowerCase().split(/\s+/).filter((t) => t.length > 2 && !STOP_WORDS.has(t));
|
|
2088
2170
|
}
|
|
2089
|
-
function
|
|
2171
|
+
function readAuditMeta(logPath) {
|
|
2172
|
+
if (!existsSync14(logPath)) return null;
|
|
2173
|
+
try {
|
|
2174
|
+
const content = readFileSync7(logPath, "utf8");
|
|
2175
|
+
const firstLine = content.split("\n")[0];
|
|
2176
|
+
if (!firstLine) return null;
|
|
2177
|
+
const parsed = JSON.parse(firstLine);
|
|
2178
|
+
if (parsed._meta && typeof parsed.lineCount === "number") {
|
|
2179
|
+
return { lineCount: parsed.lineCount };
|
|
2180
|
+
}
|
|
2181
|
+
} catch {
|
|
2182
|
+
}
|
|
2183
|
+
return null;
|
|
2184
|
+
}
|
|
2185
|
+
function writeAuditLog(brainRoot, sessionId, entries, lineCount) {
|
|
2090
2186
|
const logDir = join15(brainRoot, DIGEST_LOG_DIR);
|
|
2091
2187
|
if (!existsSync14(logDir)) {
|
|
2092
2188
|
mkdirSync9(logDir, { recursive: true });
|
|
2093
2189
|
}
|
|
2094
2190
|
const logPath = join15(logDir, `${sessionId}.jsonl`);
|
|
2095
|
-
const
|
|
2191
|
+
const metaLine = JSON.stringify({ _meta: true, lineCount, ts: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2192
|
+
const entryLines = entries.map(
|
|
2096
2193
|
(e) => JSON.stringify({
|
|
2097
2194
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2098
2195
|
path: e.correction.path,
|
|
@@ -2102,7 +2199,7 @@ function writeAuditLog(brainRoot, sessionId, entries) {
|
|
|
2102
2199
|
applied: e.applied
|
|
2103
2200
|
})
|
|
2104
2201
|
);
|
|
2105
|
-
writeFileSync11(logPath,
|
|
2202
|
+
writeFileSync11(logPath, [metaLine, ...entryLines].join("\n") + "\n", "utf8");
|
|
2106
2203
|
}
|
|
2107
2204
|
|
|
2108
2205
|
// src/evolve.ts
|
|
@@ -2566,6 +2663,7 @@ function validateActions(actions, _brain) {
|
|
|
2566
2663
|
return false;
|
|
2567
2664
|
}
|
|
2568
2665
|
const region = action.path.split("/")[0];
|
|
2666
|
+
if (region === SKILLS_DIR) return true;
|
|
2569
2667
|
if (!region || PROTECTED_REGIONS.includes(region)) {
|
|
2570
2668
|
console.log(` \u{1F6E1}\uFE0F blocked: ${action.type} ${action.path} (protected region)`);
|
|
2571
2669
|
return false;
|
|
@@ -2590,7 +2688,11 @@ function executeActions(brainRoot, actions) {
|
|
|
2590
2688
|
fireNeuron(brainRoot, action.path);
|
|
2591
2689
|
break;
|
|
2592
2690
|
case "grow":
|
|
2593
|
-
|
|
2691
|
+
if (action.path.startsWith(SKILLS_DIR + "/")) {
|
|
2692
|
+
growNeuron(brainRoot, action.path);
|
|
2693
|
+
} else {
|
|
2694
|
+
growCandidate(brainRoot, action.path);
|
|
2695
|
+
}
|
|
2594
2696
|
break;
|
|
2595
2697
|
case "signal":
|
|
2596
2698
|
signalNeuron(brainRoot, action.path, action.signal || "dopamine");
|
|
@@ -2626,6 +2728,226 @@ function actionIcon(type) {
|
|
|
2626
2728
|
return "\u2753";
|
|
2627
2729
|
}
|
|
2628
2730
|
}
|
|
2731
|
+
|
|
2732
|
+
// src/cron.ts
|
|
2733
|
+
import { writeFileSync as writeFileSync14, existsSync as existsSync17, unlinkSync } from "fs";
|
|
2734
|
+
import { join as join18 } from "path";
|
|
2735
|
+
import { execSync as execSync4 } from "child_process";
|
|
2736
|
+
var PLIST_LABEL = "com.hebbian.nightly-prune";
|
|
2737
|
+
var FEEDBACK_PLIST_LABEL = "com.hebbian.feedback";
|
|
2738
|
+
function getLaunchAgentsDir() {
|
|
2739
|
+
return join18(process.env.HOME || "~", "Library", "LaunchAgents");
|
|
2740
|
+
}
|
|
2741
|
+
function getPlistPath(label) {
|
|
2742
|
+
return join18(getLaunchAgentsDir(), `${label}.plist`);
|
|
2743
|
+
}
|
|
2744
|
+
function getNpxPath() {
|
|
2745
|
+
try {
|
|
2746
|
+
return execSync4("which npx", { encoding: "utf8" }).trim();
|
|
2747
|
+
} catch {
|
|
2748
|
+
return "/opt/homebrew/bin/npx";
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
function generatePrunePlist(brainRoot, hour = 2, minute = 0) {
|
|
2752
|
+
const npx = getNpxPath();
|
|
2753
|
+
const apiKey = process.env.GEMINI_API_KEY || "";
|
|
2754
|
+
const home = process.env.HOME || "/Users/sweetheart";
|
|
2755
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2756
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2757
|
+
<plist version="1.0">
|
|
2758
|
+
<dict>
|
|
2759
|
+
<key>Label</key>
|
|
2760
|
+
<string>${PLIST_LABEL}</string>
|
|
2761
|
+
<key>ProgramArguments</key>
|
|
2762
|
+
<array>
|
|
2763
|
+
<string>${npx}</string>
|
|
2764
|
+
<string>hebbian</string>
|
|
2765
|
+
<string>evolve</string>
|
|
2766
|
+
<string>prune</string>
|
|
2767
|
+
<string>--brain</string>
|
|
2768
|
+
<string>${brainRoot}</string>
|
|
2769
|
+
</array>
|
|
2770
|
+
<key>EnvironmentVariables</key>
|
|
2771
|
+
<dict>
|
|
2772
|
+
<key>GEMINI_API_KEY</key>
|
|
2773
|
+
<string>${apiKey}</string>
|
|
2774
|
+
<key>PATH</key>
|
|
2775
|
+
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
2776
|
+
</dict>
|
|
2777
|
+
<key>StartCalendarInterval</key>
|
|
2778
|
+
<dict>
|
|
2779
|
+
<key>Hour</key>
|
|
2780
|
+
<integer>${hour}</integer>
|
|
2781
|
+
<key>Minute</key>
|
|
2782
|
+
<integer>${minute}</integer>
|
|
2783
|
+
</dict>
|
|
2784
|
+
<key>StandardOutPath</key>
|
|
2785
|
+
<string>${home}/Library/Logs/hebbian-prune.log</string>
|
|
2786
|
+
<key>StandardErrorPath</key>
|
|
2787
|
+
<string>${home}/Library/Logs/hebbian-prune.log</string>
|
|
2788
|
+
</dict>
|
|
2789
|
+
</plist>`;
|
|
2790
|
+
}
|
|
2791
|
+
function generateFeedbackPlist(brainRoot, intervalMinutes = 15) {
|
|
2792
|
+
const npx = getNpxPath();
|
|
2793
|
+
const home = process.env.HOME || "/Users/sweetheart";
|
|
2794
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2795
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2796
|
+
<plist version="1.0">
|
|
2797
|
+
<dict>
|
|
2798
|
+
<key>Label</key>
|
|
2799
|
+
<string>${FEEDBACK_PLIST_LABEL}</string>
|
|
2800
|
+
<key>ProgramArguments</key>
|
|
2801
|
+
<array>
|
|
2802
|
+
<string>${npx}</string>
|
|
2803
|
+
<string>hebbian</string>
|
|
2804
|
+
<string>feedback</string>
|
|
2805
|
+
<string>scan</string>
|
|
2806
|
+
<string>--brain</string>
|
|
2807
|
+
<string>${brainRoot}</string>
|
|
2808
|
+
</array>
|
|
2809
|
+
<key>EnvironmentVariables</key>
|
|
2810
|
+
<dict>
|
|
2811
|
+
<key>PATH</key>
|
|
2812
|
+
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
2813
|
+
</dict>
|
|
2814
|
+
<key>StartInterval</key>
|
|
2815
|
+
<integer>${intervalMinutes * 60}</integer>
|
|
2816
|
+
<key>StandardOutPath</key>
|
|
2817
|
+
<string>${home}/Library/Logs/hebbian-feedback.log</string>
|
|
2818
|
+
<key>StandardErrorPath</key>
|
|
2819
|
+
<string>${home}/Library/Logs/hebbian-feedback.log</string>
|
|
2820
|
+
</dict>
|
|
2821
|
+
</plist>`;
|
|
2822
|
+
}
|
|
2823
|
+
function installCron(brainRoot, type = "prune") {
|
|
2824
|
+
const label = type === "prune" ? PLIST_LABEL : FEEDBACK_PLIST_LABEL;
|
|
2825
|
+
const plistPath = getPlistPath(label);
|
|
2826
|
+
const plistContent = type === "prune" ? generatePrunePlist(brainRoot) : generateFeedbackPlist(brainRoot);
|
|
2827
|
+
try {
|
|
2828
|
+
execSync4(`launchctl unload ${plistPath} 2>/dev/null`, { encoding: "utf8" });
|
|
2829
|
+
} catch {
|
|
2830
|
+
}
|
|
2831
|
+
writeFileSync14(plistPath, plistContent, "utf8");
|
|
2832
|
+
execSync4(`launchctl load ${plistPath}`, { encoding: "utf8" });
|
|
2833
|
+
console.log(`\u2705 ${type} cron installed: ${plistPath}`);
|
|
2834
|
+
}
|
|
2835
|
+
function uninstallCron(type = "prune") {
|
|
2836
|
+
const label = type === "prune" ? PLIST_LABEL : FEEDBACK_PLIST_LABEL;
|
|
2837
|
+
const plistPath = getPlistPath(label);
|
|
2838
|
+
if (!existsSync17(plistPath)) {
|
|
2839
|
+
console.log(`\u26A0\uFE0F ${type} cron not installed`);
|
|
2840
|
+
return;
|
|
2841
|
+
}
|
|
2842
|
+
try {
|
|
2843
|
+
execSync4(`launchctl unload ${plistPath}`, { encoding: "utf8" });
|
|
2844
|
+
} catch {
|
|
2845
|
+
}
|
|
2846
|
+
unlinkSync(plistPath);
|
|
2847
|
+
console.log(`\u{1F5D1}\uFE0F ${type} cron uninstalled`);
|
|
2848
|
+
}
|
|
2849
|
+
function checkCron(type = "prune") {
|
|
2850
|
+
const label = type === "prune" ? PLIST_LABEL : FEEDBACK_PLIST_LABEL;
|
|
2851
|
+
const plistPath = getPlistPath(label);
|
|
2852
|
+
return { installed: existsSync17(plistPath), path: plistPath };
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
// src/feedback.ts
|
|
2856
|
+
import { existsSync as existsSync18, readdirSync as readdirSync11, statSync as statSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync15, mkdirSync as mkdirSync11 } from "fs";
|
|
2857
|
+
import { join as join19 } from "path";
|
|
2858
|
+
var WATERMARK_FILE = "_feedback_watermark.json";
|
|
2859
|
+
var WARN_PREFIX = "WARN_shared_";
|
|
2860
|
+
function scanSharedBrain(brainRoot) {
|
|
2861
|
+
const sharedRoot = join19(brainRoot, SHARED_DIR);
|
|
2862
|
+
if (!existsSync18(sharedRoot)) return [];
|
|
2863
|
+
const watermark = readWatermark(sharedRoot);
|
|
2864
|
+
const deltas = [];
|
|
2865
|
+
for (const region of REGIONS) {
|
|
2866
|
+
const regionPath = join19(sharedRoot, region);
|
|
2867
|
+
if (!existsSync18(regionPath)) continue;
|
|
2868
|
+
walkForNeurons(regionPath, regionPath, (neuronDir, counter) => {
|
|
2869
|
+
const modTime = statSync5(neuronDir).mtime;
|
|
2870
|
+
if (modTime.getTime() <= watermark) return;
|
|
2871
|
+
const name = neuronDir.split("/").pop() || "";
|
|
2872
|
+
if (name.startsWith(WARN_PREFIX)) return;
|
|
2873
|
+
const relPath = region + "/" + neuronDir.slice(regionPath.length + 1);
|
|
2874
|
+
deltas.push({ path: relPath, counter, modTime });
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
return deltas;
|
|
2878
|
+
}
|
|
2879
|
+
function propagateToAgents(brainRoot, deltas) {
|
|
2880
|
+
const agentsDir = join19(brainRoot, AGENTS_DIR);
|
|
2881
|
+
if (!existsSync18(agentsDir) || deltas.length === 0) {
|
|
2882
|
+
return { scanned: deltas.length, propagated: 0, agents: [] };
|
|
2883
|
+
}
|
|
2884
|
+
const agentNames = readdirSync11(agentsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_")).map((e) => e.name);
|
|
2885
|
+
let propagated = 0;
|
|
2886
|
+
const touchedAgents = /* @__PURE__ */ new Set();
|
|
2887
|
+
for (const delta of deltas) {
|
|
2888
|
+
const neuronName = delta.path.split("/").pop() || "";
|
|
2889
|
+
const warnPath = delta.path.replace(/\/([^/]+)$/, `/${WARN_PREFIX}${neuronName}`);
|
|
2890
|
+
for (const agent of agentNames) {
|
|
2891
|
+
const agentBrain = join19(agentsDir, agent);
|
|
2892
|
+
if (!existsSync18(join19(agentBrain, "cortex")) && !existsSync18(join19(agentBrain, "brainstem"))) continue;
|
|
2893
|
+
try {
|
|
2894
|
+
growNeuron(agentBrain, warnPath);
|
|
2895
|
+
logEpisode(agentBrain, "feedback", warnPath, `shared learning: ${delta.path}`);
|
|
2896
|
+
propagated++;
|
|
2897
|
+
touchedAgents.add(agent);
|
|
2898
|
+
} catch {
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
return { scanned: deltas.length, propagated, agents: [...touchedAgents] };
|
|
2903
|
+
}
|
|
2904
|
+
function runFeedback(brainRoot) {
|
|
2905
|
+
const deltas = scanSharedBrain(brainRoot);
|
|
2906
|
+
if (deltas.length === 0) {
|
|
2907
|
+
console.log("\u{1F4E1} feedback: no new shared neurons");
|
|
2908
|
+
return { scanned: 0, propagated: 0, agents: [] };
|
|
2909
|
+
}
|
|
2910
|
+
const result = propagateToAgents(brainRoot, deltas);
|
|
2911
|
+
const latestTime = Math.max(...deltas.map((d) => d.modTime.getTime()));
|
|
2912
|
+
writeWatermark(join19(brainRoot, SHARED_DIR), latestTime);
|
|
2913
|
+
console.log(`\u{1F4E1} feedback: ${result.scanned} shared neuron(s) \u2192 ${result.propagated} warning(s) to ${result.agents.join(", ")}`);
|
|
2914
|
+
return result;
|
|
2915
|
+
}
|
|
2916
|
+
function readWatermark(sharedRoot) {
|
|
2917
|
+
const wmPath = join19(sharedRoot, WATERMARK_FILE);
|
|
2918
|
+
if (!existsSync18(wmPath)) return 0;
|
|
2919
|
+
try {
|
|
2920
|
+
const data = JSON.parse(readFileSync10(wmPath, "utf8"));
|
|
2921
|
+
return data.timestamp || 0;
|
|
2922
|
+
} catch {
|
|
2923
|
+
return 0;
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
function writeWatermark(sharedRoot, timestamp) {
|
|
2927
|
+
const wmPath = join19(sharedRoot, WATERMARK_FILE);
|
|
2928
|
+
mkdirSync11(sharedRoot, { recursive: true });
|
|
2929
|
+
writeFileSync15(wmPath, JSON.stringify({ timestamp, ts: new Date(timestamp).toISOString() }), "utf8");
|
|
2930
|
+
}
|
|
2931
|
+
function walkForNeurons(dir, regionRoot, cb) {
|
|
2932
|
+
let entries;
|
|
2933
|
+
try {
|
|
2934
|
+
entries = readdirSync11(dir, { withFileTypes: true });
|
|
2935
|
+
} catch {
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
const neuronFiles = entries.filter((e) => e.isFile() && /^\d+\.neuron$/.test(e.name));
|
|
2939
|
+
if (neuronFiles.length > 0) {
|
|
2940
|
+
const counter = Math.max(...neuronFiles.map((f) => parseInt(f.name, 10)));
|
|
2941
|
+
cb(dir, counter);
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
for (const entry of entries) {
|
|
2945
|
+
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
2946
|
+
if (entry.isDirectory()) {
|
|
2947
|
+
walkForNeurons(join19(dir, entry.name), regionRoot, cb);
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2629
2951
|
export {
|
|
2630
2952
|
AGENTS_DIR,
|
|
2631
2953
|
DECAY_DAYS,
|
|
@@ -2640,6 +2962,7 @@ export {
|
|
|
2640
2962
|
MAX_DEPTH,
|
|
2641
2963
|
MIN_CORRECTION_LENGTH,
|
|
2642
2964
|
OUTCOME_TYPES,
|
|
2965
|
+
PROPAGATION_EPISODE_TYPES,
|
|
2643
2966
|
PROTECTED_REGIONS_CONTRA,
|
|
2644
2967
|
REGIONS,
|
|
2645
2968
|
REGION_ICONS,
|
|
@@ -2648,10 +2971,12 @@ export {
|
|
|
2648
2971
|
SESSION_STATE_DIR,
|
|
2649
2972
|
SHARED_DIR,
|
|
2650
2973
|
SIGNAL_TYPES,
|
|
2974
|
+
SKILLS_DIR,
|
|
2651
2975
|
SPOTLIGHT_DAYS,
|
|
2652
2976
|
appendCorrection,
|
|
2653
2977
|
buildOutcomeSummary,
|
|
2654
2978
|
captureSessionStart,
|
|
2979
|
+
checkCron,
|
|
2655
2980
|
checkHooks,
|
|
2656
2981
|
classifyOutcome,
|
|
2657
2982
|
clearReports,
|
|
@@ -2668,6 +2993,8 @@ export {
|
|
|
2668
2993
|
extractCorrections,
|
|
2669
2994
|
fireNeuron,
|
|
2670
2995
|
fromCandidatePath,
|
|
2996
|
+
generateFeedbackPlist,
|
|
2997
|
+
generatePrunePlist,
|
|
2671
2998
|
getCurrentCounter,
|
|
2672
2999
|
getLastActivity,
|
|
2673
3000
|
getPendingReports,
|
|
@@ -2675,6 +3002,7 @@ export {
|
|
|
2675
3002
|
growCandidate,
|
|
2676
3003
|
growNeuron,
|
|
2677
3004
|
initBrain,
|
|
3005
|
+
installCron,
|
|
2678
3006
|
installHooks,
|
|
2679
3007
|
jaccardSimilarity,
|
|
2680
3008
|
listCandidates,
|
|
@@ -2683,6 +3011,8 @@ export {
|
|
|
2683
3011
|
printDiag,
|
|
2684
3012
|
processInbox,
|
|
2685
3013
|
promoteCandidates,
|
|
3014
|
+
propagateToAgents,
|
|
3015
|
+
propagateToShared,
|
|
2686
3016
|
readEpisodes,
|
|
2687
3017
|
readHookInput,
|
|
2688
3018
|
resolveAgentBrain,
|
|
@@ -2692,14 +3022,18 @@ export {
|
|
|
2692
3022
|
runDecay,
|
|
2693
3023
|
runDedup,
|
|
2694
3024
|
runEvolve,
|
|
3025
|
+
runFeedback,
|
|
2695
3026
|
runSubsumption,
|
|
2696
3027
|
scanBrain,
|
|
3028
|
+
scanSharedBrain,
|
|
3029
|
+
scanSkills,
|
|
2697
3030
|
signalNeuron,
|
|
2698
3031
|
startAPI,
|
|
2699
3032
|
startWatch,
|
|
2700
3033
|
stem,
|
|
2701
3034
|
toCandidatePath,
|
|
2702
3035
|
tokenize,
|
|
3036
|
+
uninstallCron,
|
|
2703
3037
|
uninstallHooks,
|
|
2704
3038
|
writeAllTiers
|
|
2705
3039
|
};
|