hebbian 0.3.2 → 0.3.3
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 +327 -117
- package/dist/bin/hebbian.js.map +1 -1
- package/dist/digest.d.ts +1 -1
- package/dist/digest.d.ts.map +1 -1
- package/dist/emit.d.ts.map +1 -1
- package/dist/grow.d.ts.map +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.js +73 -20
- package/dist/index.js.map +1 -1
- package/dist/update-check.d.ts +16 -0
- package/dist/update-check.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/bin/hebbian.js
CHANGED
|
@@ -555,6 +555,8 @@ function writeTarget(filePath, content) {
|
|
|
555
555
|
writeFileSync2(filePath, before + content + after, "utf8");
|
|
556
556
|
return;
|
|
557
557
|
}
|
|
558
|
+
writeFileSync2(filePath, content + "\n\n" + existing, "utf8");
|
|
559
|
+
return;
|
|
558
560
|
}
|
|
559
561
|
writeFileSync2(filePath, content, "utf8");
|
|
560
562
|
}
|
|
@@ -607,28 +609,174 @@ var init_emit = __esm({
|
|
|
607
609
|
}
|
|
608
610
|
});
|
|
609
611
|
|
|
612
|
+
// src/update-check.ts
|
|
613
|
+
var update_check_exports = {};
|
|
614
|
+
__export(update_check_exports, {
|
|
615
|
+
checkForUpdates: () => checkForUpdates,
|
|
616
|
+
formatUpdateBanner: () => formatUpdateBanner
|
|
617
|
+
});
|
|
618
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3, statSync as statSync2, unlinkSync } from "fs";
|
|
619
|
+
import { join as join4 } from "path";
|
|
620
|
+
function getStateDir() {
|
|
621
|
+
return join4(process.env.HOME || "~", ".hebbian");
|
|
622
|
+
}
|
|
623
|
+
function ensureStateDir(stateDir) {
|
|
624
|
+
if (!existsSync5(stateDir)) {
|
|
625
|
+
mkdirSync3(stateDir, { recursive: true });
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function isCacheStale(cachePath, type) {
|
|
629
|
+
try {
|
|
630
|
+
const mtime = statSync2(cachePath).mtimeMs;
|
|
631
|
+
const ageMinutes = (Date.now() - mtime) / 1e3 / 60;
|
|
632
|
+
const ttl = type === "UP_TO_DATE" ? TTL_UP_TO_DATE : TTL_UPGRADE_AVAILABLE;
|
|
633
|
+
return ageMinutes > ttl;
|
|
634
|
+
} catch {
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
function readCache(stateDir) {
|
|
639
|
+
const cachePath = join4(stateDir, "last-update-check");
|
|
640
|
+
if (!existsSync5(cachePath)) return null;
|
|
641
|
+
try {
|
|
642
|
+
const line = readFileSync3(cachePath, "utf8").trim();
|
|
643
|
+
if (line.startsWith("UP_TO_DATE")) {
|
|
644
|
+
if (isCacheStale(cachePath, "UP_TO_DATE")) return null;
|
|
645
|
+
const ver = line.split(/\s+/)[1];
|
|
646
|
+
return { type: "UP_TO_DATE", current: ver };
|
|
647
|
+
}
|
|
648
|
+
if (line.startsWith("UPGRADE_AVAILABLE")) {
|
|
649
|
+
if (isCacheStale(cachePath, "UPGRADE_AVAILABLE")) return null;
|
|
650
|
+
const [, current, latest] = line.split(/\s+/);
|
|
651
|
+
return { type: "UPGRADE_AVAILABLE", current, latest };
|
|
652
|
+
}
|
|
653
|
+
return null;
|
|
654
|
+
} catch {
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
function writeCache(stateDir, line) {
|
|
659
|
+
ensureStateDir(stateDir);
|
|
660
|
+
writeFileSync3(join4(stateDir, "last-update-check"), line, "utf8");
|
|
661
|
+
}
|
|
662
|
+
function isSnoozed(stateDir, remoteVersion) {
|
|
663
|
+
const snoozePath = join4(stateDir, "update-snoozed");
|
|
664
|
+
if (!existsSync5(snoozePath)) return false;
|
|
665
|
+
try {
|
|
666
|
+
const [ver, levelStr, epochStr] = readFileSync3(snoozePath, "utf8").trim().split(/\s+/);
|
|
667
|
+
if (ver !== remoteVersion) {
|
|
668
|
+
unlinkSync(snoozePath);
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
const level = parseInt(levelStr || "1", 10);
|
|
672
|
+
const epoch = parseInt(epochStr || "0", 10);
|
|
673
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
674
|
+
const duration = SNOOZE_DURATIONS[Math.min(level, 3)] ?? SNOOZE_DURATIONS[3];
|
|
675
|
+
return now < epoch + duration;
|
|
676
|
+
} catch {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
async function fetchLatestVersion() {
|
|
681
|
+
try {
|
|
682
|
+
const controller = new AbortController();
|
|
683
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
684
|
+
const res = await fetch(NPM_REGISTRY_URL, {
|
|
685
|
+
signal: controller.signal,
|
|
686
|
+
headers: { Accept: "application/json" }
|
|
687
|
+
});
|
|
688
|
+
clearTimeout(timeout);
|
|
689
|
+
if (!res.ok) return null;
|
|
690
|
+
const data = await res.json();
|
|
691
|
+
const version = data.version;
|
|
692
|
+
if (!version || !/^\d+\.\d+[\d.]*$/.test(version)) return null;
|
|
693
|
+
return version;
|
|
694
|
+
} catch {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
async function checkForUpdates(currentVersion) {
|
|
699
|
+
if (process.env.HEBBIAN_UPDATE_CHECK === "false") {
|
|
700
|
+
return { type: "skipped" };
|
|
701
|
+
}
|
|
702
|
+
const stateDir = getStateDir();
|
|
703
|
+
const cached = readCache(stateDir);
|
|
704
|
+
if (cached) {
|
|
705
|
+
if (cached.type === "UP_TO_DATE") {
|
|
706
|
+
return { type: "up_to_date" };
|
|
707
|
+
}
|
|
708
|
+
if (cached.type === "UPGRADE_AVAILABLE" && cached.current && cached.latest) {
|
|
709
|
+
if (cached.current === currentVersion && !isSnoozed(stateDir, cached.latest)) {
|
|
710
|
+
return { type: "upgrade_available", current: currentVersion, latest: cached.latest };
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const latest = await fetchLatestVersion();
|
|
715
|
+
if (!latest) {
|
|
716
|
+
writeCache(stateDir, `UP_TO_DATE ${currentVersion}`);
|
|
717
|
+
return { type: "up_to_date" };
|
|
718
|
+
}
|
|
719
|
+
if (latest === currentVersion) {
|
|
720
|
+
writeCache(stateDir, `UP_TO_DATE ${currentVersion}`);
|
|
721
|
+
return { type: "up_to_date" };
|
|
722
|
+
}
|
|
723
|
+
writeCache(stateDir, `UPGRADE_AVAILABLE ${currentVersion} ${latest}`);
|
|
724
|
+
if (isSnoozed(stateDir, latest)) {
|
|
725
|
+
return { type: "up_to_date" };
|
|
726
|
+
}
|
|
727
|
+
return { type: "upgrade_available", current: currentVersion, latest };
|
|
728
|
+
}
|
|
729
|
+
function formatUpdateBanner(status) {
|
|
730
|
+
if (status.type !== "upgrade_available") return null;
|
|
731
|
+
return [
|
|
732
|
+
``,
|
|
733
|
+
` \u26A1 hebbian v${status.latest} available (current: v${status.current})`,
|
|
734
|
+
` npm i -g hebbian@latest`,
|
|
735
|
+
``
|
|
736
|
+
].join("\n");
|
|
737
|
+
}
|
|
738
|
+
var PACKAGE_NAME, NPM_REGISTRY_URL, FETCH_TIMEOUT_MS, TTL_UP_TO_DATE, TTL_UPGRADE_AVAILABLE, SNOOZE_DURATIONS;
|
|
739
|
+
var init_update_check = __esm({
|
|
740
|
+
"src/update-check.ts"() {
|
|
741
|
+
"use strict";
|
|
742
|
+
PACKAGE_NAME = "hebbian";
|
|
743
|
+
NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
744
|
+
FETCH_TIMEOUT_MS = 5e3;
|
|
745
|
+
TTL_UP_TO_DATE = 60;
|
|
746
|
+
TTL_UPGRADE_AVAILABLE = 720;
|
|
747
|
+
SNOOZE_DURATIONS = {
|
|
748
|
+
1: 86400,
|
|
749
|
+
// 24h
|
|
750
|
+
2: 172800,
|
|
751
|
+
// 48h
|
|
752
|
+
3: 604800
|
|
753
|
+
// 7d (and beyond)
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
|
|
610
758
|
// src/fire.ts
|
|
611
759
|
var fire_exports = {};
|
|
612
760
|
__export(fire_exports, {
|
|
613
761
|
fireNeuron: () => fireNeuron,
|
|
614
762
|
getCurrentCounter: () => getCurrentCounter
|
|
615
763
|
});
|
|
616
|
-
import { readdirSync as readdirSync3, renameSync, writeFileSync as
|
|
617
|
-
import { join as
|
|
764
|
+
import { readdirSync as readdirSync3, renameSync, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
765
|
+
import { join as join5 } from "path";
|
|
618
766
|
function fireNeuron(brainRoot, neuronPath) {
|
|
619
|
-
const fullPath =
|
|
620
|
-
if (!
|
|
621
|
-
|
|
622
|
-
|
|
767
|
+
const fullPath = join5(brainRoot, neuronPath);
|
|
768
|
+
if (!existsSync6(fullPath)) {
|
|
769
|
+
mkdirSync4(fullPath, { recursive: true });
|
|
770
|
+
writeFileSync4(join5(fullPath, "1.neuron"), "", "utf8");
|
|
623
771
|
console.log(`\u{1F331} grew + fired: ${neuronPath} (1)`);
|
|
624
772
|
return 1;
|
|
625
773
|
}
|
|
626
774
|
const current = getCurrentCounter(fullPath);
|
|
627
775
|
const newCounter = current + 1;
|
|
628
776
|
if (current > 0) {
|
|
629
|
-
renameSync(
|
|
777
|
+
renameSync(join5(fullPath, `${current}.neuron`), join5(fullPath, `${newCounter}.neuron`));
|
|
630
778
|
} else {
|
|
631
|
-
|
|
779
|
+
writeFileSync4(join5(fullPath, `${newCounter}.neuron`), "", "utf8");
|
|
632
780
|
}
|
|
633
781
|
console.log(`\u{1F525} fired: ${neuronPath} (${current} \u2192 ${newCounter})`);
|
|
634
782
|
return newCounter;
|
|
@@ -654,7 +802,7 @@ var init_fire = __esm({
|
|
|
654
802
|
|
|
655
803
|
// src/similarity.ts
|
|
656
804
|
function tokenize(name) {
|
|
657
|
-
return name.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[
|
|
805
|
+
return name.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9\u3000-\u9FFF\uAC00-\uD7AF]+/g, " ").toLowerCase().split(" ").map(stem).filter((t) => t.length > 1);
|
|
658
806
|
}
|
|
659
807
|
function stem(word) {
|
|
660
808
|
const suffixes = ["ing", "tion", "sion", "ness", "ment", "able", "ible", "ful", "less", "ous", "ive", "ity", "ies", "ed", "er", "es", "ly", "al", "en"];
|
|
@@ -688,11 +836,11 @@ var grow_exports = {};
|
|
|
688
836
|
__export(grow_exports, {
|
|
689
837
|
growNeuron: () => growNeuron
|
|
690
838
|
});
|
|
691
|
-
import { mkdirSync as
|
|
692
|
-
import { join as
|
|
839
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, existsSync as existsSync7, readdirSync as readdirSync4 } from "fs";
|
|
840
|
+
import { join as join6, relative as relative2 } from "path";
|
|
693
841
|
function growNeuron(brainRoot, neuronPath) {
|
|
694
|
-
const fullPath =
|
|
695
|
-
if (
|
|
842
|
+
const fullPath = join6(brainRoot, neuronPath);
|
|
843
|
+
if (existsSync7(fullPath)) {
|
|
696
844
|
const counter = fireNeuron(brainRoot, neuronPath);
|
|
697
845
|
return { action: "fired", path: neuronPath, counter };
|
|
698
846
|
}
|
|
@@ -702,10 +850,12 @@ function growNeuron(brainRoot, neuronPath) {
|
|
|
702
850
|
throw new Error(`Invalid region: ${regionName}. Valid: ${REGIONS.join(", ")}`);
|
|
703
851
|
}
|
|
704
852
|
const leafName = parts[parts.length - 1];
|
|
705
|
-
const
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
|
|
853
|
+
const newPrefix = leafName.match(/^(NO|DO|MUST|WARN)_/)?.[1] || "";
|
|
854
|
+
const newStripped = leafName.replace(/^(NO|DO|MUST|WARN)_/, "");
|
|
855
|
+
const newTokens = tokenize(newStripped);
|
|
856
|
+
const regionPath = join6(brainRoot, regionName);
|
|
857
|
+
if (existsSync7(regionPath)) {
|
|
858
|
+
const match = findSimilar(regionPath, regionPath, newTokens, newPrefix);
|
|
709
859
|
if (match) {
|
|
710
860
|
const matchRelPath = regionName + "/" + relative2(regionPath, match);
|
|
711
861
|
console.log(`\u{1F504} consolidation: "${neuronPath}" \u2248 "${matchRelPath}" (firing existing)`);
|
|
@@ -713,12 +863,12 @@ function growNeuron(brainRoot, neuronPath) {
|
|
|
713
863
|
return { action: "fired", path: matchRelPath, counter };
|
|
714
864
|
}
|
|
715
865
|
}
|
|
716
|
-
|
|
717
|
-
|
|
866
|
+
mkdirSync5(fullPath, { recursive: true });
|
|
867
|
+
writeFileSync5(join6(fullPath, "1.neuron"), "", "utf8");
|
|
718
868
|
console.log(`\u{1F331} grew: ${neuronPath} (1)`);
|
|
719
869
|
return { action: "grew", path: neuronPath, counter: 1 };
|
|
720
870
|
}
|
|
721
|
-
function findSimilar(dir, regionRoot, targetTokens) {
|
|
871
|
+
function findSimilar(dir, regionRoot, targetTokens, targetPrefix) {
|
|
722
872
|
let entries;
|
|
723
873
|
try {
|
|
724
874
|
entries = readdirSync4(dir, { withFileTypes: true });
|
|
@@ -728,16 +878,19 @@ function findSimilar(dir, regionRoot, targetTokens) {
|
|
|
728
878
|
const hasNeuron = entries.some((e) => e.isFile() && e.name.endsWith(".neuron"));
|
|
729
879
|
if (hasNeuron) {
|
|
730
880
|
const folderName = dir.split("/").pop() || "";
|
|
731
|
-
const
|
|
881
|
+
const existingPrefix = folderName.match(/^(NO|DO|MUST|WARN)_/)?.[1] || "";
|
|
882
|
+
const existingStripped = folderName.replace(/^(NO|DO|MUST|WARN)_/, "");
|
|
883
|
+
const existingTokens = tokenize(existingStripped);
|
|
732
884
|
const similarity = jaccardSimilarity(targetTokens, existingTokens);
|
|
733
|
-
if (
|
|
885
|
+
if (targetPrefix !== existingPrefix && targetTokens.length <= 2) {
|
|
886
|
+
} else if (similarity >= JACCARD_THRESHOLD) {
|
|
734
887
|
return dir;
|
|
735
888
|
}
|
|
736
889
|
}
|
|
737
890
|
for (const entry of entries) {
|
|
738
891
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
739
892
|
if (entry.isDirectory()) {
|
|
740
|
-
const match = findSimilar(
|
|
893
|
+
const match = findSimilar(join6(dir, entry.name), regionRoot, targetTokens, targetPrefix);
|
|
741
894
|
if (match) return match;
|
|
742
895
|
}
|
|
743
896
|
}
|
|
@@ -758,9 +911,9 @@ __export(rollback_exports, {
|
|
|
758
911
|
rollbackNeuron: () => rollbackNeuron
|
|
759
912
|
});
|
|
760
913
|
import { renameSync as renameSync2 } from "fs";
|
|
761
|
-
import { join as
|
|
914
|
+
import { join as join7 } from "path";
|
|
762
915
|
function rollbackNeuron(brainRoot, neuronPath) {
|
|
763
|
-
const fullPath =
|
|
916
|
+
const fullPath = join7(brainRoot, neuronPath);
|
|
764
917
|
const current = getCurrentCounter(fullPath);
|
|
765
918
|
if (current === 0) {
|
|
766
919
|
throw new Error(`Neuron not found: ${neuronPath}`);
|
|
@@ -769,7 +922,7 @@ function rollbackNeuron(brainRoot, neuronPath) {
|
|
|
769
922
|
throw new Error(`Counter already at minimum (1): ${neuronPath}`);
|
|
770
923
|
}
|
|
771
924
|
const newCounter = current - 1;
|
|
772
|
-
renameSync2(
|
|
925
|
+
renameSync2(join7(fullPath, `${current}.neuron`), join7(fullPath, `${newCounter}.neuron`));
|
|
773
926
|
console.log(`\u23EA rollback: ${neuronPath} (${current} \u2192 ${newCounter})`);
|
|
774
927
|
return newCounter;
|
|
775
928
|
}
|
|
@@ -785,31 +938,31 @@ var signal_exports = {};
|
|
|
785
938
|
__export(signal_exports, {
|
|
786
939
|
signalNeuron: () => signalNeuron
|
|
787
940
|
});
|
|
788
|
-
import { writeFileSync as
|
|
789
|
-
import { join as
|
|
941
|
+
import { writeFileSync as writeFileSync6, existsSync as existsSync8, readdirSync as readdirSync5 } from "fs";
|
|
942
|
+
import { join as join8 } from "path";
|
|
790
943
|
function signalNeuron(brainRoot, neuronPath, signalType) {
|
|
791
944
|
if (!SIGNAL_TYPES.includes(signalType)) {
|
|
792
945
|
throw new Error(`Invalid signal type: ${signalType}. Valid: ${SIGNAL_TYPES.join(", ")}`);
|
|
793
946
|
}
|
|
794
|
-
const fullPath =
|
|
795
|
-
if (!
|
|
947
|
+
const fullPath = join8(brainRoot, neuronPath);
|
|
948
|
+
if (!existsSync8(fullPath)) {
|
|
796
949
|
throw new Error(`Neuron not found: ${neuronPath}`);
|
|
797
950
|
}
|
|
798
951
|
switch (signalType) {
|
|
799
952
|
case "bomb": {
|
|
800
|
-
|
|
953
|
+
writeFileSync6(join8(fullPath, "bomb.neuron"), "", "utf8");
|
|
801
954
|
console.log(`\u{1F4A3} bomb planted: ${neuronPath}`);
|
|
802
955
|
break;
|
|
803
956
|
}
|
|
804
957
|
case "dopamine": {
|
|
805
958
|
const level = getNextSignalLevel(fullPath, "dopamine");
|
|
806
|
-
|
|
959
|
+
writeFileSync6(join8(fullPath, `dopamine${level}.neuron`), "", "utf8");
|
|
807
960
|
console.log(`\u{1F7E2} dopamine +${level}: ${neuronPath}`);
|
|
808
961
|
break;
|
|
809
962
|
}
|
|
810
963
|
case "memory": {
|
|
811
964
|
const level = getNextSignalLevel(fullPath, "memory");
|
|
812
|
-
|
|
965
|
+
writeFileSync6(join8(fullPath, `memory${level}.neuron`), "", "utf8");
|
|
813
966
|
console.log(`\u{1F4BE} memory +${level}: ${neuronPath}`);
|
|
814
967
|
break;
|
|
815
968
|
}
|
|
@@ -840,15 +993,15 @@ var decay_exports = {};
|
|
|
840
993
|
__export(decay_exports, {
|
|
841
994
|
runDecay: () => runDecay
|
|
842
995
|
});
|
|
843
|
-
import { readdirSync as readdirSync6, statSync as
|
|
844
|
-
import { join as
|
|
996
|
+
import { readdirSync as readdirSync6, statSync as statSync3, writeFileSync as writeFileSync7, existsSync as existsSync9 } from "fs";
|
|
997
|
+
import { join as join9 } from "path";
|
|
845
998
|
function runDecay(brainRoot, days) {
|
|
846
999
|
const threshold = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
847
1000
|
let scanned = 0;
|
|
848
1001
|
let decayed = 0;
|
|
849
1002
|
for (const regionName of REGIONS) {
|
|
850
|
-
const regionPath =
|
|
851
|
-
if (!
|
|
1003
|
+
const regionPath = join9(brainRoot, regionName);
|
|
1004
|
+
if (!existsSync9(regionPath)) continue;
|
|
852
1005
|
const result = decayWalk(regionPath, threshold, 0);
|
|
853
1006
|
scanned += result.scanned;
|
|
854
1007
|
decayed += result.decayed;
|
|
@@ -874,7 +1027,7 @@ function decayWalk(dir, threshold, depth) {
|
|
|
874
1027
|
if (entry.name.endsWith(".neuron")) {
|
|
875
1028
|
hasNeuronFile = true;
|
|
876
1029
|
try {
|
|
877
|
-
const st =
|
|
1030
|
+
const st = statSync3(join9(dir, entry.name));
|
|
878
1031
|
if (st.mtimeMs > latestMod) latestMod = st.mtimeMs;
|
|
879
1032
|
} catch {
|
|
880
1033
|
}
|
|
@@ -888,8 +1041,8 @@ function decayWalk(dir, threshold, depth) {
|
|
|
888
1041
|
scanned++;
|
|
889
1042
|
if (!isDormant && latestMod < threshold) {
|
|
890
1043
|
const age = Math.floor((Date.now() - latestMod) / (24 * 60 * 60 * 1e3));
|
|
891
|
-
|
|
892
|
-
|
|
1044
|
+
writeFileSync7(
|
|
1045
|
+
join9(dir, "decay.dormant"),
|
|
893
1046
|
`Dormant since ${(/* @__PURE__ */ new Date()).toISOString()} (${age} days inactive)`,
|
|
894
1047
|
"utf8"
|
|
895
1048
|
);
|
|
@@ -899,7 +1052,7 @@ function decayWalk(dir, threshold, depth) {
|
|
|
899
1052
|
for (const entry of entries) {
|
|
900
1053
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
901
1054
|
if (entry.isDirectory()) {
|
|
902
|
-
const sub = decayWalk(
|
|
1055
|
+
const sub = decayWalk(join9(dir, entry.name), threshold, depth + 1);
|
|
903
1056
|
scanned += sub.scanned;
|
|
904
1057
|
decayed += sub.decayed;
|
|
905
1058
|
}
|
|
@@ -918,8 +1071,8 @@ var dedup_exports = {};
|
|
|
918
1071
|
__export(dedup_exports, {
|
|
919
1072
|
runDedup: () => runDedup
|
|
920
1073
|
});
|
|
921
|
-
import { writeFileSync as
|
|
922
|
-
import { join as
|
|
1074
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
1075
|
+
import { join as join10 } from "path";
|
|
923
1076
|
function runDedup(brainRoot) {
|
|
924
1077
|
const brain = scanBrain(brainRoot);
|
|
925
1078
|
let scanned = 0;
|
|
@@ -941,8 +1094,8 @@ function runDedup(brainRoot) {
|
|
|
941
1094
|
const [keep, drop] = ni.counter >= nj.counter ? [ni, nj] : [nj, ni];
|
|
942
1095
|
const relKeep = `${region.name}/${keep.path}`;
|
|
943
1096
|
fireNeuron(brainRoot, relKeep);
|
|
944
|
-
|
|
945
|
-
|
|
1097
|
+
writeFileSync8(
|
|
1098
|
+
join10(drop.fullPath, "dedup.dormant"),
|
|
946
1099
|
`Merged into ${keep.path} on ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
947
1100
|
"utf8"
|
|
948
1101
|
);
|
|
@@ -972,10 +1125,10 @@ __export(snapshot_exports, {
|
|
|
972
1125
|
gitSnapshot: () => gitSnapshot
|
|
973
1126
|
});
|
|
974
1127
|
import { execSync } from "child_process";
|
|
975
|
-
import { existsSync as
|
|
976
|
-
import { join as
|
|
1128
|
+
import { existsSync as existsSync10 } from "fs";
|
|
1129
|
+
import { join as join11 } from "path";
|
|
977
1130
|
function gitSnapshot(brainRoot) {
|
|
978
|
-
if (!
|
|
1131
|
+
if (!existsSync10(join11(brainRoot, ".git"))) {
|
|
979
1132
|
try {
|
|
980
1133
|
execSync("git rev-parse --is-inside-work-tree", { cwd: brainRoot, stdio: "pipe" });
|
|
981
1134
|
} catch {
|
|
@@ -1064,12 +1217,12 @@ var init_watch = __esm({
|
|
|
1064
1217
|
});
|
|
1065
1218
|
|
|
1066
1219
|
// src/episode.ts
|
|
1067
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
1068
|
-
import { join as
|
|
1220
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync9, mkdirSync as mkdirSync6, existsSync as existsSync11 } from "fs";
|
|
1221
|
+
import { join as join12 } from "path";
|
|
1069
1222
|
function logEpisode(brainRoot, type, path, detail) {
|
|
1070
|
-
const logDir =
|
|
1071
|
-
if (!
|
|
1072
|
-
|
|
1223
|
+
const logDir = join12(brainRoot, SESSION_LOG_DIR);
|
|
1224
|
+
if (!existsSync11(logDir)) {
|
|
1225
|
+
mkdirSync6(logDir, { recursive: true });
|
|
1073
1226
|
}
|
|
1074
1227
|
const nextSlot = getNextSlot(logDir);
|
|
1075
1228
|
const episode = {
|
|
@@ -1078,8 +1231,8 @@ function logEpisode(brainRoot, type, path, detail) {
|
|
|
1078
1231
|
path,
|
|
1079
1232
|
detail
|
|
1080
1233
|
};
|
|
1081
|
-
|
|
1082
|
-
|
|
1234
|
+
writeFileSync9(
|
|
1235
|
+
join12(logDir, `memory${nextSlot}.neuron`),
|
|
1083
1236
|
JSON.stringify(episode),
|
|
1084
1237
|
"utf8"
|
|
1085
1238
|
);
|
|
@@ -1114,14 +1267,14 @@ __export(inbox_exports, {
|
|
|
1114
1267
|
ensureInbox: () => ensureInbox,
|
|
1115
1268
|
processInbox: () => processInbox
|
|
1116
1269
|
});
|
|
1117
|
-
import { readFileSync as
|
|
1118
|
-
import { join as
|
|
1270
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync10, existsSync as existsSync12, mkdirSync as mkdirSync7 } from "fs";
|
|
1271
|
+
import { join as join13 } from "path";
|
|
1119
1272
|
function processInbox(brainRoot) {
|
|
1120
|
-
const inboxPath =
|
|
1121
|
-
if (!
|
|
1273
|
+
const inboxPath = join13(brainRoot, INBOX_DIR, CORRECTIONS_FILE);
|
|
1274
|
+
if (!existsSync12(inboxPath)) {
|
|
1122
1275
|
return { processed: 0, skipped: 0, errors: [] };
|
|
1123
1276
|
}
|
|
1124
|
-
const content =
|
|
1277
|
+
const content = readFileSync5(inboxPath, "utf8").trim();
|
|
1125
1278
|
if (!content) {
|
|
1126
1279
|
return { processed: 0, skipped: 0, errors: [] };
|
|
1127
1280
|
}
|
|
@@ -1162,7 +1315,7 @@ function processInbox(brainRoot) {
|
|
|
1162
1315
|
skipped++;
|
|
1163
1316
|
}
|
|
1164
1317
|
}
|
|
1165
|
-
|
|
1318
|
+
writeFileSync10(inboxPath, "", "utf8");
|
|
1166
1319
|
console.log(`\u{1F4E5} inbox: processed ${processed}, skipped ${skipped}`);
|
|
1167
1320
|
if (errors.length > 0) {
|
|
1168
1321
|
for (const err of errors) {
|
|
@@ -1173,9 +1326,9 @@ function processInbox(brainRoot) {
|
|
|
1173
1326
|
}
|
|
1174
1327
|
function applyCorrection(brainRoot, correction) {
|
|
1175
1328
|
const neuronPath = correction.path;
|
|
1176
|
-
const fullPath =
|
|
1329
|
+
const fullPath = join13(brainRoot, neuronPath);
|
|
1177
1330
|
const counterAdd = Math.max(1, correction.counter_add || 1);
|
|
1178
|
-
if (
|
|
1331
|
+
if (existsSync12(fullPath)) {
|
|
1179
1332
|
for (let i = 0; i < counterAdd; i++) {
|
|
1180
1333
|
fireNeuron(brainRoot, neuronPath);
|
|
1181
1334
|
}
|
|
@@ -1201,21 +1354,21 @@ function isPathSafe(path) {
|
|
|
1201
1354
|
return true;
|
|
1202
1355
|
}
|
|
1203
1356
|
function ensureInbox(brainRoot) {
|
|
1204
|
-
const inboxDir =
|
|
1205
|
-
if (!
|
|
1206
|
-
|
|
1357
|
+
const inboxDir = join13(brainRoot, INBOX_DIR);
|
|
1358
|
+
if (!existsSync12(inboxDir)) {
|
|
1359
|
+
mkdirSync7(inboxDir, { recursive: true });
|
|
1207
1360
|
}
|
|
1208
|
-
const filePath =
|
|
1209
|
-
if (!
|
|
1210
|
-
|
|
1361
|
+
const filePath = join13(inboxDir, CORRECTIONS_FILE);
|
|
1362
|
+
if (!existsSync12(filePath)) {
|
|
1363
|
+
writeFileSync10(filePath, "", "utf8");
|
|
1211
1364
|
}
|
|
1212
1365
|
return filePath;
|
|
1213
1366
|
}
|
|
1214
1367
|
function appendCorrection(brainRoot, correction) {
|
|
1215
1368
|
const filePath = ensureInbox(brainRoot);
|
|
1216
1369
|
const line = JSON.stringify(correction) + "\n";
|
|
1217
|
-
const existing =
|
|
1218
|
-
|
|
1370
|
+
const existing = readFileSync5(filePath, "utf8");
|
|
1371
|
+
writeFileSync10(filePath, existing + line, "utf8");
|
|
1219
1372
|
}
|
|
1220
1373
|
var INBOX_DIR, CORRECTIONS_FILE, DOPAMINE_ALLOWED_ROLES;
|
|
1221
1374
|
var init_inbox = __esm({
|
|
@@ -1519,22 +1672,28 @@ __export(hooks_exports, {
|
|
|
1519
1672
|
installHooks: () => installHooks,
|
|
1520
1673
|
uninstallHooks: () => uninstallHooks
|
|
1521
1674
|
});
|
|
1522
|
-
import { readFileSync as
|
|
1523
|
-
import {
|
|
1675
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync11, existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync8 } from "fs";
|
|
1676
|
+
import { execSync as execSync2 } from "child_process";
|
|
1677
|
+
import { join as join14, resolve as resolve2 } from "path";
|
|
1524
1678
|
function installHooks(brainRoot, projectRoot) {
|
|
1525
1679
|
const root = projectRoot || process.cwd();
|
|
1526
1680
|
const resolvedBrain = resolve2(brainRoot);
|
|
1527
|
-
if (!
|
|
1681
|
+
if (!existsSync13(resolvedBrain) || !hasBrainRegions(resolvedBrain)) {
|
|
1528
1682
|
initBrain(resolvedBrain);
|
|
1529
1683
|
}
|
|
1530
|
-
const settingsDir =
|
|
1531
|
-
const settingsPath =
|
|
1684
|
+
const settingsDir = join14(root, SETTINGS_DIR);
|
|
1685
|
+
const settingsPath = join14(settingsDir, SETTINGS_FILE);
|
|
1532
1686
|
const defaultBrain = resolve2(root, "brain");
|
|
1533
1687
|
const brainFlag = resolvedBrain === defaultBrain ? "" : ` --brain ${resolvedBrain}`;
|
|
1688
|
+
let npxBin = "npx";
|
|
1689
|
+
try {
|
|
1690
|
+
npxBin = execSync2("which npx", { encoding: "utf8" }).trim();
|
|
1691
|
+
} catch {
|
|
1692
|
+
}
|
|
1534
1693
|
let settings = {};
|
|
1535
|
-
if (
|
|
1694
|
+
if (existsSync13(settingsPath)) {
|
|
1536
1695
|
try {
|
|
1537
|
-
settings = JSON.parse(
|
|
1696
|
+
settings = JSON.parse(readFileSync6(settingsPath, "utf8"));
|
|
1538
1697
|
} catch {
|
|
1539
1698
|
console.log(`\u26A0\uFE0F settings.local.json was malformed, overwriting`);
|
|
1540
1699
|
}
|
|
@@ -1549,7 +1708,7 @@ function installHooks(brainRoot, projectRoot) {
|
|
|
1549
1708
|
matcher: "startup|resume",
|
|
1550
1709
|
entry: {
|
|
1551
1710
|
type: "command",
|
|
1552
|
-
command:
|
|
1711
|
+
command: `${npxBin} hebbian emit claude${brainFlag}`,
|
|
1553
1712
|
timeout: 10,
|
|
1554
1713
|
statusMessage: `${HOOK_MARKER} refreshing brain`
|
|
1555
1714
|
}
|
|
@@ -1558,7 +1717,7 @@ function installHooks(brainRoot, projectRoot) {
|
|
|
1558
1717
|
event: "Stop",
|
|
1559
1718
|
entry: {
|
|
1560
1719
|
type: "command",
|
|
1561
|
-
command:
|
|
1720
|
+
command: `${npxBin} hebbian digest${brainFlag}`,
|
|
1562
1721
|
timeout: 30,
|
|
1563
1722
|
statusMessage: `${HOOK_MARKER} digesting session`
|
|
1564
1723
|
}
|
|
@@ -1581,24 +1740,24 @@ function installHooks(brainRoot, projectRoot) {
|
|
|
1581
1740
|
hooks[event].push(group);
|
|
1582
1741
|
}
|
|
1583
1742
|
}
|
|
1584
|
-
if (!
|
|
1585
|
-
|
|
1743
|
+
if (!existsSync13(settingsDir)) {
|
|
1744
|
+
mkdirSync8(settingsDir, { recursive: true });
|
|
1586
1745
|
}
|
|
1587
|
-
|
|
1746
|
+
writeFileSync11(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1588
1747
|
console.log(`\u2705 hebbian hooks installed at ${settingsPath}`);
|
|
1589
|
-
console.log(` SessionStart \u2192 hebbian emit claude${brainFlag}`);
|
|
1590
|
-
console.log(` Stop \u2192 hebbian digest${brainFlag}`);
|
|
1748
|
+
console.log(` SessionStart \u2192 ${npxBin} hebbian emit claude${brainFlag}`);
|
|
1749
|
+
console.log(` Stop \u2192 ${npxBin} hebbian digest${brainFlag}`);
|
|
1591
1750
|
}
|
|
1592
1751
|
function uninstallHooks(projectRoot) {
|
|
1593
1752
|
const root = projectRoot || process.cwd();
|
|
1594
|
-
const settingsPath =
|
|
1595
|
-
if (!
|
|
1753
|
+
const settingsPath = join14(root, SETTINGS_DIR, SETTINGS_FILE);
|
|
1754
|
+
if (!existsSync13(settingsPath)) {
|
|
1596
1755
|
console.log("No hooks installed (settings.local.json not found)");
|
|
1597
1756
|
return;
|
|
1598
1757
|
}
|
|
1599
1758
|
let settings;
|
|
1600
1759
|
try {
|
|
1601
|
-
settings = JSON.parse(
|
|
1760
|
+
settings = JSON.parse(readFileSync6(settingsPath, "utf8"));
|
|
1602
1761
|
} catch {
|
|
1603
1762
|
console.log("settings.local.json is malformed, nothing to uninstall");
|
|
1604
1763
|
return;
|
|
@@ -1622,24 +1781,24 @@ function uninstallHooks(projectRoot) {
|
|
|
1622
1781
|
if (Object.keys(hooks).length === 0) {
|
|
1623
1782
|
delete settings.hooks;
|
|
1624
1783
|
}
|
|
1625
|
-
|
|
1784
|
+
writeFileSync11(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1626
1785
|
console.log(`\u2705 removed ${removed} hebbian hook(s) from ${settingsPath}`);
|
|
1627
1786
|
}
|
|
1628
1787
|
function checkHooks(projectRoot) {
|
|
1629
1788
|
const root = projectRoot || process.cwd();
|
|
1630
|
-
const settingsPath =
|
|
1789
|
+
const settingsPath = join14(root, SETTINGS_DIR, SETTINGS_FILE);
|
|
1631
1790
|
const status = {
|
|
1632
1791
|
installed: false,
|
|
1633
1792
|
path: settingsPath,
|
|
1634
1793
|
events: []
|
|
1635
1794
|
};
|
|
1636
|
-
if (!
|
|
1795
|
+
if (!existsSync13(settingsPath)) {
|
|
1637
1796
|
console.log(`\u274C hebbian hooks not installed (${settingsPath} not found)`);
|
|
1638
1797
|
return status;
|
|
1639
1798
|
}
|
|
1640
1799
|
let settings;
|
|
1641
1800
|
try {
|
|
1642
|
-
settings = JSON.parse(
|
|
1801
|
+
settings = JSON.parse(readFileSync6(settingsPath, "utf8"));
|
|
1643
1802
|
} catch {
|
|
1644
1803
|
console.log(`\u274C settings.local.json is malformed`);
|
|
1645
1804
|
return status;
|
|
@@ -1669,7 +1828,7 @@ function checkHooks(projectRoot) {
|
|
|
1669
1828
|
return status;
|
|
1670
1829
|
}
|
|
1671
1830
|
function hasBrainRegions(dir) {
|
|
1672
|
-
if (!
|
|
1831
|
+
if (!existsSync13(dir)) return false;
|
|
1673
1832
|
try {
|
|
1674
1833
|
const entries = readdirSync8(dir);
|
|
1675
1834
|
return REGIONS.some((r) => entries.includes(r));
|
|
@@ -1695,8 +1854,8 @@ __export(digest_exports, {
|
|
|
1695
1854
|
extractCorrections: () => extractCorrections,
|
|
1696
1855
|
readHookInput: () => readHookInput
|
|
1697
1856
|
});
|
|
1698
|
-
import { readFileSync as
|
|
1699
|
-
import { join as
|
|
1857
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync12, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
1858
|
+
import { join as join15, basename } from "path";
|
|
1700
1859
|
function readHookInput(stdin) {
|
|
1701
1860
|
if (!stdin.trim()) return null;
|
|
1702
1861
|
try {
|
|
@@ -1711,13 +1870,13 @@ function readHookInput(stdin) {
|
|
|
1711
1870
|
}
|
|
1712
1871
|
}
|
|
1713
1872
|
function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
1714
|
-
if (!
|
|
1873
|
+
if (!existsSync14(transcriptPath)) {
|
|
1715
1874
|
throw new Error(`Transcript not found: ${transcriptPath}`);
|
|
1716
1875
|
}
|
|
1717
1876
|
const resolvedSessionId = sessionId || basename(transcriptPath, ".jsonl");
|
|
1718
|
-
const logDir =
|
|
1719
|
-
const logPath =
|
|
1720
|
-
if (
|
|
1877
|
+
const logDir = join15(brainRoot, DIGEST_LOG_DIR);
|
|
1878
|
+
const logPath = join15(logDir, `${resolvedSessionId}.jsonl`);
|
|
1879
|
+
if (existsSync14(logPath)) {
|
|
1721
1880
|
console.log(`\u23ED already digested session ${resolvedSessionId}, skip`);
|
|
1722
1881
|
return { corrections: 0, skipped: 0, transcriptPath, sessionId: resolvedSessionId };
|
|
1723
1882
|
}
|
|
@@ -1751,7 +1910,7 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
1751
1910
|
};
|
|
1752
1911
|
}
|
|
1753
1912
|
function parseTranscript(transcriptPath) {
|
|
1754
|
-
const content =
|
|
1913
|
+
const content = readFileSync7(transcriptPath, "utf8");
|
|
1755
1914
|
const lines = content.split("\n").filter(Boolean);
|
|
1756
1915
|
const messages = [];
|
|
1757
1916
|
for (const line of lines) {
|
|
@@ -1793,17 +1952,24 @@ function extractCorrections(messages) {
|
|
|
1793
1952
|
}
|
|
1794
1953
|
function detectCorrection(text) {
|
|
1795
1954
|
const isNegation = NEGATION_PATTERNS.some((p) => p.test(text));
|
|
1955
|
+
const isMust = MUST_PATTERNS.some((p) => p.test(text));
|
|
1956
|
+
const isWarn = WARN_PATTERNS.some((p) => p.test(text));
|
|
1796
1957
|
const isAffirmation = AFFIRMATION_PATTERNS.some((p) => p.test(text));
|
|
1797
|
-
if (!isNegation && !isAffirmation) return null;
|
|
1798
|
-
|
|
1958
|
+
if (!isNegation && !isMust && !isWarn && !isAffirmation) return null;
|
|
1959
|
+
let prefix;
|
|
1960
|
+
if (isNegation) prefix = "NO";
|
|
1961
|
+
else if (isMust) prefix = "MUST";
|
|
1962
|
+
else if (isWarn) prefix = "WARN";
|
|
1963
|
+
else prefix = "DO";
|
|
1799
1964
|
const keywords = extractKeywords(text);
|
|
1800
1965
|
if (keywords.length === 0) return null;
|
|
1801
|
-
const pathSegment = `${prefix}_${keywords.slice(0,
|
|
1966
|
+
const pathSegment = `${prefix}_${keywords.slice(0, 3).join("_")}`;
|
|
1802
1967
|
const path = `cortex/${pathSegment}`;
|
|
1803
1968
|
return { text, path, prefix, keywords };
|
|
1804
1969
|
}
|
|
1805
1970
|
function extractKeywords(text) {
|
|
1806
1971
|
const STOP_WORDS = /* @__PURE__ */ new Set([
|
|
1972
|
+
// English stop words
|
|
1807
1973
|
"the",
|
|
1808
1974
|
"a",
|
|
1809
1975
|
"an",
|
|
@@ -1885,7 +2051,6 @@ function extractKeywords(text) {
|
|
|
1885
2051
|
"those",
|
|
1886
2052
|
"it",
|
|
1887
2053
|
"its",
|
|
1888
|
-
"i",
|
|
1889
2054
|
"me",
|
|
1890
2055
|
"my",
|
|
1891
2056
|
"we",
|
|
@@ -1914,17 +2079,40 @@ function extractKeywords(text) {
|
|
|
1914
2079
|
"should",
|
|
1915
2080
|
"like",
|
|
1916
2081
|
"want",
|
|
1917
|
-
"think"
|
|
2082
|
+
"think",
|
|
2083
|
+
"way",
|
|
2084
|
+
"make",
|
|
2085
|
+
"sure",
|
|
2086
|
+
"keep",
|
|
2087
|
+
"try",
|
|
2088
|
+
"let",
|
|
2089
|
+
"get",
|
|
2090
|
+
"put",
|
|
2091
|
+
"set",
|
|
2092
|
+
"new",
|
|
2093
|
+
"also",
|
|
2094
|
+
"using",
|
|
2095
|
+
"used",
|
|
2096
|
+
"when",
|
|
2097
|
+
"where",
|
|
2098
|
+
"how",
|
|
2099
|
+
"why",
|
|
2100
|
+
"here",
|
|
2101
|
+
"there",
|
|
2102
|
+
"careful",
|
|
2103
|
+
"warning",
|
|
2104
|
+
"watch",
|
|
2105
|
+
"out",
|
|
2106
|
+
"required"
|
|
1918
2107
|
]);
|
|
1919
|
-
|
|
1920
|
-
return tokens.filter((t) => !STOP_WORDS.has(t) && t.length > 2);
|
|
2108
|
+
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));
|
|
1921
2109
|
}
|
|
1922
2110
|
function writeAuditLog(brainRoot, sessionId, entries) {
|
|
1923
|
-
const logDir =
|
|
1924
|
-
if (!
|
|
1925
|
-
|
|
2111
|
+
const logDir = join15(brainRoot, DIGEST_LOG_DIR);
|
|
2112
|
+
if (!existsSync14(logDir)) {
|
|
2113
|
+
mkdirSync9(logDir, { recursive: true });
|
|
1926
2114
|
}
|
|
1927
|
-
const logPath =
|
|
2115
|
+
const logPath = join15(logDir, `${sessionId}.jsonl`);
|
|
1928
2116
|
const lines = entries.map(
|
|
1929
2117
|
(e) => JSON.stringify({
|
|
1930
2118
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1935,16 +2123,15 @@ function writeAuditLog(brainRoot, sessionId, entries) {
|
|
|
1935
2123
|
applied: e.applied
|
|
1936
2124
|
})
|
|
1937
2125
|
);
|
|
1938
|
-
|
|
2126
|
+
writeFileSync12(logPath, lines.join("\n") + (lines.length > 0 ? "\n" : ""), "utf8");
|
|
1939
2127
|
}
|
|
1940
|
-
var NEGATION_PATTERNS, AFFIRMATION_PATTERNS;
|
|
2128
|
+
var NEGATION_PATTERNS, AFFIRMATION_PATTERNS, MUST_PATTERNS, WARN_PATTERNS;
|
|
1941
2129
|
var init_digest = __esm({
|
|
1942
2130
|
"src/digest.ts"() {
|
|
1943
2131
|
"use strict";
|
|
1944
2132
|
init_constants();
|
|
1945
2133
|
init_grow();
|
|
1946
2134
|
init_episode();
|
|
1947
|
-
init_similarity();
|
|
1948
2135
|
NEGATION_PATTERNS = [
|
|
1949
2136
|
/\bdon[''\u2019]?t\b/i,
|
|
1950
2137
|
/\bdo not\b/i,
|
|
@@ -1963,13 +2150,24 @@ var init_digest = __esm({
|
|
|
1963
2150
|
];
|
|
1964
2151
|
AFFIRMATION_PATTERNS = [
|
|
1965
2152
|
/\balways\b/i,
|
|
1966
|
-
/\bmust\b/i,
|
|
1967
2153
|
/\bshould\s+always\b/i,
|
|
1968
2154
|
/\buse\s+\w+\s+instead\b/i,
|
|
1969
2155
|
// Korean affirmation
|
|
1970
|
-
|
|
2156
|
+
/항상/
|
|
2157
|
+
];
|
|
2158
|
+
MUST_PATTERNS = [
|
|
2159
|
+
/\bmust\b/i,
|
|
2160
|
+
/\brequired\b/i,
|
|
2161
|
+
// Korean
|
|
1971
2162
|
/반드시/
|
|
1972
2163
|
];
|
|
2164
|
+
WARN_PATTERNS = [
|
|
2165
|
+
/\bcareful\b/i,
|
|
2166
|
+
/\bwatch\s+out\b/i,
|
|
2167
|
+
/\bwarning\b/i,
|
|
2168
|
+
// Korean
|
|
2169
|
+
/주의/
|
|
2170
|
+
];
|
|
1973
2171
|
}
|
|
1974
2172
|
});
|
|
1975
2173
|
|
|
@@ -2075,6 +2273,12 @@ async function main(argv) {
|
|
|
2075
2273
|
}
|
|
2076
2274
|
const { emitToTarget: emitToTarget2 } = await Promise.resolve().then(() => (init_emit(), emit_exports));
|
|
2077
2275
|
await emitToTarget2(brainRoot, target);
|
|
2276
|
+
const { checkForUpdates: checkForUpdates2, formatUpdateBanner: formatUpdateBanner2 } = await Promise.resolve().then(() => (init_update_check(), update_check_exports));
|
|
2277
|
+
checkForUpdates2(VERSION).then((status) => {
|
|
2278
|
+
const banner = formatUpdateBanner2(status);
|
|
2279
|
+
if (banner) console.error(banner);
|
|
2280
|
+
}).catch(() => {
|
|
2281
|
+
});
|
|
2078
2282
|
break;
|
|
2079
2283
|
}
|
|
2080
2284
|
case "fire": {
|
|
@@ -2164,9 +2368,15 @@ async function main(argv) {
|
|
|
2164
2368
|
case "uninstall":
|
|
2165
2369
|
uninstallHooks2();
|
|
2166
2370
|
break;
|
|
2167
|
-
case "status":
|
|
2371
|
+
case "status": {
|
|
2168
2372
|
checkHooks2();
|
|
2373
|
+
console.log(` version: v${VERSION}`);
|
|
2374
|
+
const { checkForUpdates: checkUpdates, formatUpdateBanner: formatBanner } = await Promise.resolve().then(() => (init_update_check(), update_check_exports));
|
|
2375
|
+
const updateStatus = await checkUpdates(VERSION);
|
|
2376
|
+
const updateBanner = formatBanner(updateStatus);
|
|
2377
|
+
if (updateBanner) console.error(updateBanner);
|
|
2169
2378
|
break;
|
|
2379
|
+
}
|
|
2170
2380
|
default:
|
|
2171
2381
|
console.error("Usage: hebbian claude <install|uninstall|status>");
|
|
2172
2382
|
process.exit(1);
|