@hiveai/core 0.10.9 → 0.12.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/dist/index.d.ts +314 -1
- package/dist/index.js +376 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,14 @@ var SensorSchema = z.object({
|
|
|
46
46
|
/** ISO timestamp of the last time this sensor matched a diff. */
|
|
47
47
|
last_fired: z.string().nullable().default(null)
|
|
48
48
|
});
|
|
49
|
+
var ActivationSchema = z.object({
|
|
50
|
+
/** Case-insensitive substrings matched against the task text. */
|
|
51
|
+
keywords: z.array(z.string()).default([]),
|
|
52
|
+
/** Glob-ish path patterns matched against the files being edited. */
|
|
53
|
+
globs: z.array(z.string()).default([]),
|
|
54
|
+
/** Always activate (rare — for truly universal playbooks). */
|
|
55
|
+
always: z.boolean().default(false)
|
|
56
|
+
});
|
|
49
57
|
var IsoDateString = z.union([z.string(), z.date()]).transform((v) => v instanceof Date ? v.toISOString() : v).pipe(z.string().datetime());
|
|
50
58
|
var MemoryFrontmatterSchema = z.object({
|
|
51
59
|
id: z.string().min(1),
|
|
@@ -56,6 +64,8 @@ var MemoryFrontmatterSchema = z.object({
|
|
|
56
64
|
anchor: AnchorSchema.default({ paths: [], symbols: [] }),
|
|
57
65
|
/** Optional executable check derived from this memory (feedback computational layer). */
|
|
58
66
|
sensor: SensorSchema.optional(),
|
|
67
|
+
/** Optional progressive-disclosure triggers — only meaningful for `type: skill`. */
|
|
68
|
+
activation: ActivationSchema.optional(),
|
|
59
69
|
tags: z.array(z.string()).default([]),
|
|
60
70
|
domain: z.string().optional(),
|
|
61
71
|
author: z.string().optional(),
|
|
@@ -149,6 +159,7 @@ function buildFrontmatter(input) {
|
|
|
149
159
|
expires_when: null,
|
|
150
160
|
topic: input.topic,
|
|
151
161
|
sensor: input.sensor,
|
|
162
|
+
activation: input.activation,
|
|
152
163
|
revision_count: 0,
|
|
153
164
|
related_ids: input.relatedIds ?? []
|
|
154
165
|
});
|
|
@@ -583,9 +594,14 @@ function emptyUsage() {
|
|
|
583
594
|
last_read_at: null,
|
|
584
595
|
rejected_count: 0,
|
|
585
596
|
last_rejected_at: null,
|
|
586
|
-
rejection_reason: null
|
|
597
|
+
rejection_reason: null,
|
|
598
|
+
applied_count: 0,
|
|
599
|
+
last_applied_at: null
|
|
587
600
|
};
|
|
588
601
|
}
|
|
602
|
+
function normalizeUsage(stored) {
|
|
603
|
+
return { ...emptyUsage(), ...stored ?? {} };
|
|
604
|
+
}
|
|
589
605
|
function emptyUsageIndex() {
|
|
590
606
|
return {
|
|
591
607
|
version: 1,
|
|
@@ -615,13 +631,13 @@ async function saveUsageIndex(paths, index) {
|
|
|
615
631
|
await writeFile(file, JSON.stringify(index, null, 2), "utf8");
|
|
616
632
|
}
|
|
617
633
|
function getUsage(index, id) {
|
|
618
|
-
return index.by_id[id]
|
|
634
|
+
return normalizeUsage(index.by_id[id]);
|
|
619
635
|
}
|
|
620
636
|
function bumpRead(index, ids) {
|
|
621
637
|
if (ids.length === 0) return index;
|
|
622
638
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
623
639
|
for (const id of ids) {
|
|
624
|
-
const current = index.by_id[id]
|
|
640
|
+
const current = normalizeUsage(index.by_id[id]);
|
|
625
641
|
index.by_id[id] = {
|
|
626
642
|
...current,
|
|
627
643
|
read_count: current.read_count + 1,
|
|
@@ -631,7 +647,7 @@ function bumpRead(index, ids) {
|
|
|
631
647
|
return index;
|
|
632
648
|
}
|
|
633
649
|
function recordRejection(index, id, reason) {
|
|
634
|
-
const current = index.by_id[id]
|
|
650
|
+
const current = normalizeUsage(index.by_id[id]);
|
|
635
651
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
636
652
|
index.by_id[id] = {
|
|
637
653
|
...current,
|
|
@@ -641,6 +657,16 @@ function recordRejection(index, id, reason) {
|
|
|
641
657
|
};
|
|
642
658
|
return index;
|
|
643
659
|
}
|
|
660
|
+
function recordApplied(index, id) {
|
|
661
|
+
const current = normalizeUsage(index.by_id[id]);
|
|
662
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
663
|
+
index.by_id[id] = {
|
|
664
|
+
...current,
|
|
665
|
+
applied_count: current.applied_count + 1,
|
|
666
|
+
last_applied_at: now
|
|
667
|
+
};
|
|
668
|
+
return index;
|
|
669
|
+
}
|
|
644
670
|
var DECAY_DAYS = 90;
|
|
645
671
|
function isDecaying(usage, createdAt) {
|
|
646
672
|
const threshold = Date.now() - DECAY_DAYS * 24 * 60 * 60 * 1e3;
|
|
@@ -657,6 +683,206 @@ async function trackReads(paths, ids) {
|
|
|
657
683
|
return index;
|
|
658
684
|
}
|
|
659
685
|
|
|
686
|
+
// src/impact.ts
|
|
687
|
+
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
688
|
+
var DEFAULT_DORMANT_DAYS = 120;
|
|
689
|
+
var READ_SATURATION = 32;
|
|
690
|
+
function clamp01(n) {
|
|
691
|
+
if (Number.isNaN(n)) return 0;
|
|
692
|
+
return Math.max(0, Math.min(1, n));
|
|
693
|
+
}
|
|
694
|
+
function hasSensorFired(fm) {
|
|
695
|
+
return Boolean(fm.sensor?.last_fired);
|
|
696
|
+
}
|
|
697
|
+
function isDeadStatus(fm) {
|
|
698
|
+
return fm.status === "stale" || fm.status === "deprecated" || fm.status === "rejected";
|
|
699
|
+
}
|
|
700
|
+
function computeImpact(fm, usage, options = {}) {
|
|
701
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
702
|
+
const dormantDays = options.dormantDays ?? DEFAULT_DORMANT_DAYS;
|
|
703
|
+
const signals = [];
|
|
704
|
+
let raw = 0;
|
|
705
|
+
if (usage.read_count > 0) {
|
|
706
|
+
raw += Math.min(1, Math.log2(usage.read_count + 1) / Math.log2(READ_SATURATION + 1)) * 0.35;
|
|
707
|
+
signals.push(`read ${usage.read_count}\xD7`);
|
|
708
|
+
}
|
|
709
|
+
if (usage.applied_count > 0) {
|
|
710
|
+
raw += Math.min(1, usage.applied_count / 4) * 0.6;
|
|
711
|
+
signals.push(`applied ${usage.applied_count}\xD7`);
|
|
712
|
+
}
|
|
713
|
+
if (hasSensorFired(fm)) {
|
|
714
|
+
raw += 0.25;
|
|
715
|
+
signals.push("sensor fired");
|
|
716
|
+
}
|
|
717
|
+
if (usage.rejected_count > 0) {
|
|
718
|
+
raw -= Math.min(0.6, usage.rejected_count * 0.25);
|
|
719
|
+
signals.push(`rejected ${usage.rejected_count}\xD7`);
|
|
720
|
+
}
|
|
721
|
+
let score = clamp01(raw);
|
|
722
|
+
if (isDeadStatus(fm)) {
|
|
723
|
+
score *= 0.2;
|
|
724
|
+
signals.push(`status=${fm.status}`);
|
|
725
|
+
}
|
|
726
|
+
const anchor = usage.last_applied_at ?? usage.last_read_at ?? fm.created_at;
|
|
727
|
+
const ageDays = (now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY;
|
|
728
|
+
const dormant = Number.isFinite(ageDays) && ageDays >= dormantDays && usage.applied_count === 0;
|
|
729
|
+
if (dormant) {
|
|
730
|
+
score *= 0.5;
|
|
731
|
+
signals.push(`dormant ${Math.floor(ageDays)}d`);
|
|
732
|
+
}
|
|
733
|
+
const tier = deriveTier(score, dormant, usage);
|
|
734
|
+
const pruneCandidate = isPruneCandidate(fm, usage, tier);
|
|
735
|
+
return { score: round3(score), tier, signals, pruneCandidate };
|
|
736
|
+
}
|
|
737
|
+
function deriveTier(score, dormant, usage) {
|
|
738
|
+
if (dormant && usage.read_count <= 1 && usage.applied_count === 0) return "dormant";
|
|
739
|
+
if (score >= 0.55) return "high";
|
|
740
|
+
if (score >= 0.2) return "medium";
|
|
741
|
+
return "low";
|
|
742
|
+
}
|
|
743
|
+
function isPruneCandidate(fm, usage, tier) {
|
|
744
|
+
if (fm.sensor || usage.applied_count > 0) return false;
|
|
745
|
+
if (isDeadStatus(fm)) return true;
|
|
746
|
+
if (usage.rejected_count > 0 && usage.rejected_count >= usage.read_count) return true;
|
|
747
|
+
if (tier === "dormant" && usage.read_count === 0) return true;
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
750
|
+
function round3(n) {
|
|
751
|
+
return Math.round(n * 1e3) / 1e3;
|
|
752
|
+
}
|
|
753
|
+
function compareImpact(a, b) {
|
|
754
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
755
|
+
if (a.pruneCandidate !== b.pruneCandidate) return a.pruneCandidate ? 1 : -1;
|
|
756
|
+
return 0;
|
|
757
|
+
}
|
|
758
|
+
function summarizeImpact(scores) {
|
|
759
|
+
const summary = {
|
|
760
|
+
total: scores.length,
|
|
761
|
+
high: 0,
|
|
762
|
+
medium: 0,
|
|
763
|
+
low: 0,
|
|
764
|
+
dormant: 0,
|
|
765
|
+
prune_candidates: 0
|
|
766
|
+
};
|
|
767
|
+
for (const s of scores) {
|
|
768
|
+
summary[s.tier] += 1;
|
|
769
|
+
if (s.pruneCandidate) summary.prune_candidates += 1;
|
|
770
|
+
}
|
|
771
|
+
return summary;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// src/eval.ts
|
|
775
|
+
function round32(n) {
|
|
776
|
+
return Math.round(n * 1e3) / 1e3;
|
|
777
|
+
}
|
|
778
|
+
function uniq(ids) {
|
|
779
|
+
return [...new Set(ids)];
|
|
780
|
+
}
|
|
781
|
+
function scoreRetrievalCase(name, expectIds, surfacedRanked) {
|
|
782
|
+
const expect = uniq(expectIds);
|
|
783
|
+
const surfaced = uniq(surfacedRanked);
|
|
784
|
+
const surfacedSet = new Set(surfaced);
|
|
785
|
+
const hits = expect.filter((id) => surfacedSet.has(id));
|
|
786
|
+
const misses = expect.filter((id) => !surfacedSet.has(id));
|
|
787
|
+
let bestRank = null;
|
|
788
|
+
for (let i = 0; i < surfaced.length; i++) {
|
|
789
|
+
if (expect.includes(surfaced[i])) {
|
|
790
|
+
bestRank = i + 1;
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return {
|
|
795
|
+
name,
|
|
796
|
+
expect_ids: expect,
|
|
797
|
+
surfaced_ids: surfaced,
|
|
798
|
+
hits,
|
|
799
|
+
misses,
|
|
800
|
+
precision: surfaced.length === 0 ? 0 : round32(hits.length / surfaced.length),
|
|
801
|
+
recall: expect.length === 0 ? 1 : round32(hits.length / expect.length),
|
|
802
|
+
best_rank: bestRank
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
function aggregateRetrieval(cases) {
|
|
806
|
+
const n = cases.length;
|
|
807
|
+
const mean = (sel) => n === 0 ? 0 : round32(cases.reduce((s, c) => s + sel(c), 0) / n);
|
|
808
|
+
return {
|
|
809
|
+
cases,
|
|
810
|
+
mean_precision: mean((c) => c.precision),
|
|
811
|
+
mean_recall: mean((c) => c.recall),
|
|
812
|
+
mrr: mean((c) => c.best_rank ? 1 / c.best_rank : 0)
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function scoreSensorCase(name, expectFireIds, firedIds) {
|
|
816
|
+
const expect = uniq(expectFireIds);
|
|
817
|
+
const fired = uniq(firedIds);
|
|
818
|
+
const firedSet = new Set(fired);
|
|
819
|
+
const hits = expect.filter((id) => firedSet.has(id));
|
|
820
|
+
const misses = expect.filter((id) => !firedSet.has(id));
|
|
821
|
+
return {
|
|
822
|
+
name,
|
|
823
|
+
expect_fire_ids: expect,
|
|
824
|
+
fired_ids: fired,
|
|
825
|
+
hits,
|
|
826
|
+
misses,
|
|
827
|
+
recall: expect.length === 0 ? 1 : round32(hits.length / expect.length)
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
function aggregateSensors(cases) {
|
|
831
|
+
const totalExpected = cases.reduce((s, c) => s + c.expect_fire_ids.length, 0);
|
|
832
|
+
const totalHits = cases.reduce((s, c) => s + c.hits.length, 0);
|
|
833
|
+
return {
|
|
834
|
+
cases,
|
|
835
|
+
catch_rate: totalExpected === 0 ? 1 : round32(totalHits / totalExpected)
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
function overallScore(retrieval, sensors) {
|
|
839
|
+
if (retrieval && sensors) {
|
|
840
|
+
return Math.round((0.5 * retrieval.mean_recall + 0.2 * retrieval.mrr + 0.3 * sensors.catch_rate) * 100);
|
|
841
|
+
}
|
|
842
|
+
if (retrieval) {
|
|
843
|
+
return Math.round((0.7 * retrieval.mean_recall + 0.3 * retrieval.mrr) * 100);
|
|
844
|
+
}
|
|
845
|
+
if (sensors) {
|
|
846
|
+
return Math.round(sensors.catch_rate * 100);
|
|
847
|
+
}
|
|
848
|
+
return 0;
|
|
849
|
+
}
|
|
850
|
+
function buildReport(retrieval, sensors) {
|
|
851
|
+
return { retrieval, sensors, score: overallScore(retrieval, sensors) };
|
|
852
|
+
}
|
|
853
|
+
function titleFromBody(body) {
|
|
854
|
+
const lines = body.split("\n");
|
|
855
|
+
for (const line of lines) {
|
|
856
|
+
const heading = /^#+\s*(.+)$/.exec(line.trim());
|
|
857
|
+
if (heading) return heading[1].trim().slice(0, 120);
|
|
858
|
+
}
|
|
859
|
+
for (const line of lines) {
|
|
860
|
+
const t = line.trim();
|
|
861
|
+
if (t) return t.replace(/^[-*]\s*/, "").slice(0, 120);
|
|
862
|
+
}
|
|
863
|
+
return "";
|
|
864
|
+
}
|
|
865
|
+
function synthesizeSelfEvalCases(memories, options = {}) {
|
|
866
|
+
const includeFiles = options.includeFiles ?? true;
|
|
867
|
+
const skip = new Set(options.skipStatuses ?? ["stale", "deprecated", "rejected"]);
|
|
868
|
+
const cases = [];
|
|
869
|
+
for (const { memory } of memories) {
|
|
870
|
+
const fm = memory.frontmatter;
|
|
871
|
+
if (fm.type === "session_recap") continue;
|
|
872
|
+
if (skip.has(fm.status)) continue;
|
|
873
|
+
const paths = fm.anchor.paths;
|
|
874
|
+
if (paths.length === 0) continue;
|
|
875
|
+
const task = titleFromBody(memory.body) || fm.id;
|
|
876
|
+
cases.push({
|
|
877
|
+
name: fm.id,
|
|
878
|
+
task,
|
|
879
|
+
...includeFiles ? { files: paths } : {},
|
|
880
|
+
expect_ids: [fm.id]
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
return cases;
|
|
884
|
+
}
|
|
885
|
+
|
|
660
886
|
// src/confidence.ts
|
|
661
887
|
var DEFAULT_CONFIDENCE_THRESHOLDS = {
|
|
662
888
|
trustedReads: 3,
|
|
@@ -664,13 +890,13 @@ var DEFAULT_CONFIDENCE_THRESHOLDS = {
|
|
|
664
890
|
decayDays: 180,
|
|
665
891
|
hardDecayDays: 365
|
|
666
892
|
};
|
|
667
|
-
var
|
|
893
|
+
var MS_PER_DAY2 = 24 * 60 * 60 * 1e3;
|
|
668
894
|
function deriveConfidence(fm, usage, thresholds = DEFAULT_CONFIDENCE_THRESHOLDS, now = /* @__PURE__ */ new Date()) {
|
|
669
895
|
if (fm.status === "stale" || fm.status === "deprecated" || fm.status === "rejected") return "stale";
|
|
670
896
|
const baseLevel = baseConfidence(fm, usage, thresholds);
|
|
671
897
|
if (baseLevel !== "authoritative" && baseLevel !== "trusted") return baseLevel;
|
|
672
898
|
const anchor = usage.last_read_at ?? fm.created_at;
|
|
673
|
-
const ageDays = (now.getTime() - new Date(anchor).getTime()) /
|
|
899
|
+
const ageDays = (now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY2;
|
|
674
900
|
if (Number.isNaN(ageDays) || ageDays <= 0) return baseLevel;
|
|
675
901
|
if (ageDays >= thresholds.hardDecayDays) {
|
|
676
902
|
return "low";
|
|
@@ -700,6 +926,122 @@ function isAutoPromoteEligible(fm, usage, rule = DEFAULT_AUTO_PROMOTE_RULE) {
|
|
|
700
926
|
return usage.read_count >= rule.minReads;
|
|
701
927
|
}
|
|
702
928
|
|
|
929
|
+
// src/distinctive.ts
|
|
930
|
+
var CODE_STOPWORDS = /* @__PURE__ */ new Set([
|
|
931
|
+
"import",
|
|
932
|
+
"export",
|
|
933
|
+
"function",
|
|
934
|
+
"return",
|
|
935
|
+
"const",
|
|
936
|
+
"let",
|
|
937
|
+
"var",
|
|
938
|
+
"class",
|
|
939
|
+
"public",
|
|
940
|
+
"private",
|
|
941
|
+
"protected",
|
|
942
|
+
"static",
|
|
943
|
+
"this",
|
|
944
|
+
"true",
|
|
945
|
+
"false",
|
|
946
|
+
"null",
|
|
947
|
+
"undefined",
|
|
948
|
+
"void",
|
|
949
|
+
"async",
|
|
950
|
+
"await",
|
|
951
|
+
"from",
|
|
952
|
+
"type",
|
|
953
|
+
"interface",
|
|
954
|
+
"extends",
|
|
955
|
+
"implements",
|
|
956
|
+
"number",
|
|
957
|
+
"string",
|
|
958
|
+
"boolean",
|
|
959
|
+
"value",
|
|
960
|
+
"default",
|
|
961
|
+
"case",
|
|
962
|
+
"break",
|
|
963
|
+
"continue",
|
|
964
|
+
"throw",
|
|
965
|
+
"catch",
|
|
966
|
+
"finally",
|
|
967
|
+
"else",
|
|
968
|
+
"while",
|
|
969
|
+
"for",
|
|
970
|
+
"new",
|
|
971
|
+
"super",
|
|
972
|
+
"yield",
|
|
973
|
+
"module",
|
|
974
|
+
"require",
|
|
975
|
+
"console"
|
|
976
|
+
]);
|
|
977
|
+
var MIN_WORD_LEN = 4;
|
|
978
|
+
function tokenizeWords(text) {
|
|
979
|
+
return text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= MIN_WORD_LEN && !CODE_STOPWORDS.has(t));
|
|
980
|
+
}
|
|
981
|
+
function buildDocFrequency(bodies) {
|
|
982
|
+
const df = /* @__PURE__ */ new Map();
|
|
983
|
+
for (const body of bodies) {
|
|
984
|
+
const unique = new Set(tokenizeWords(body));
|
|
985
|
+
for (const tok of unique) df.set(tok, (df.get(tok) ?? 0) + 1);
|
|
986
|
+
}
|
|
987
|
+
return { df, total: bodies.length };
|
|
988
|
+
}
|
|
989
|
+
function distinctiveCap(total) {
|
|
990
|
+
return Math.max(1, Math.floor(0.1 * total));
|
|
991
|
+
}
|
|
992
|
+
function isDistinctiveToken(token, freq) {
|
|
993
|
+
const tok = token.toLowerCase();
|
|
994
|
+
if (tok.length < MIN_WORD_LEN || CODE_STOPWORDS.has(tok)) return false;
|
|
995
|
+
const df = freq.df.get(tok);
|
|
996
|
+
if (df === void 0) return true;
|
|
997
|
+
return df <= distinctiveCap(freq.total);
|
|
998
|
+
}
|
|
999
|
+
function diffHasDistinctiveOverlap(addedDiffText, memoryBody, freq) {
|
|
1000
|
+
const memoryTokens = new Set(tokenizeWords(memoryBody));
|
|
1001
|
+
if (memoryTokens.size === 0) return false;
|
|
1002
|
+
for (const tok of new Set(tokenizeWords(addedDiffText))) {
|
|
1003
|
+
if (memoryTokens.has(tok) && isDistinctiveToken(tok, freq)) return true;
|
|
1004
|
+
}
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// src/skill-activation.ts
|
|
1009
|
+
function isSkill(fm) {
|
|
1010
|
+
return fm.type === "skill";
|
|
1011
|
+
}
|
|
1012
|
+
function evaluateSkillActivation(fm, ctx) {
|
|
1013
|
+
if (!isSkill(fm)) return { applicable: false, activated: true, reasons: [] };
|
|
1014
|
+
const act = fm.activation;
|
|
1015
|
+
if (!act) return { applicable: false, activated: true, reasons: ["no-activation"] };
|
|
1016
|
+
const reasons = [];
|
|
1017
|
+
if (act.always) reasons.push("always");
|
|
1018
|
+
const task = (ctx.task ?? "").toLowerCase();
|
|
1019
|
+
if (task) {
|
|
1020
|
+
for (const kw of act.keywords) {
|
|
1021
|
+
if (kw && task.includes(kw.toLowerCase())) {
|
|
1022
|
+
reasons.push(`keyword:${kw}`);
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
const files = ctx.files ?? [];
|
|
1028
|
+
if (files.length > 0) {
|
|
1029
|
+
outer: for (const glob of act.globs) {
|
|
1030
|
+
for (const f of files) {
|
|
1031
|
+
if (pathsOverlap(glob, f)) {
|
|
1032
|
+
reasons.push(`glob:${glob}`);
|
|
1033
|
+
break outer;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return { applicable: true, activated: reasons.length > 0, reasons };
|
|
1039
|
+
}
|
|
1040
|
+
function isSkillSuppressed(fm, ctx) {
|
|
1041
|
+
const result = evaluateSkillActivation(fm, ctx);
|
|
1042
|
+
return result.applicable && !result.activated;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
703
1045
|
// src/specificity.ts
|
|
704
1046
|
var GENERIC_PHRASES = [
|
|
705
1047
|
"validate input",
|
|
@@ -2631,7 +2973,7 @@ function pickLowercaseValuePattern(text) {
|
|
|
2631
2973
|
for (const match of text.matchAll(/\blowercase\s+([A-Za-z][A-Za-z0-9_.:-]{2,79})\s+([a-z][a-z0-9_.:-]{1,40})\b/g)) {
|
|
2632
2974
|
const key = match[1] ?? "";
|
|
2633
2975
|
const value = match[2] ?? "";
|
|
2634
|
-
if (!
|
|
2976
|
+
if (!isDistinctiveToken2(key, true) || isBoringValue(value)) continue;
|
|
2635
2977
|
candidates.push({
|
|
2636
2978
|
label: `${key}=${value}`,
|
|
2637
2979
|
pattern: `${escapeRegExp(key)}\\s*[:=]\\s*["']?${escapeRegExp(value)}["']?`,
|
|
@@ -2647,7 +2989,7 @@ function pickAssignmentPattern(text) {
|
|
|
2647
2989
|
const key = match[1] ?? "";
|
|
2648
2990
|
const operator = match[2] ?? "";
|
|
2649
2991
|
const value = match[3] ?? "";
|
|
2650
|
-
if (!
|
|
2992
|
+
if (!isDistinctiveToken2(key, true) || isBoringValue(value)) continue;
|
|
2651
2993
|
const label = `${key}${operator}${value}`;
|
|
2652
2994
|
candidates.push({
|
|
2653
2995
|
label,
|
|
@@ -2678,7 +3020,7 @@ function pickDistinctiveToken(text) {
|
|
|
2678
3020
|
const raw = (match[1] ?? match[2] ?? match[3] ?? "").trim();
|
|
2679
3021
|
const token = raw.replace(/^[^\w.-]+|[^\w.-]+$/g, "");
|
|
2680
3022
|
const isCodeLike = Boolean(match[1] ?? match[2]);
|
|
2681
|
-
if (!
|
|
3023
|
+
if (!isDistinctiveToken2(token, isCodeLike)) continue;
|
|
2682
3024
|
const key = token.toLowerCase();
|
|
2683
3025
|
const codeSpanBonus = match[1] ? 20 : match[2] ? 8 : 0;
|
|
2684
3026
|
const shapeBonus = /[-_.:]/.test(token) ? 3 : /[A-Z]/.test(token.slice(1)) ? 2 : /\d/.test(token) ? 1 : 0;
|
|
@@ -2689,7 +3031,7 @@ function pickDistinctiveToken(text) {
|
|
|
2689
3031
|
const best = [...candidates.values()].sort((a, b) => b.score - a.score)[0];
|
|
2690
3032
|
return best?.raw ?? null;
|
|
2691
3033
|
}
|
|
2692
|
-
function
|
|
3034
|
+
function isDistinctiveToken2(token, isCodeLike) {
|
|
2693
3035
|
if (token.length < 4 || token.length > 80) return false;
|
|
2694
3036
|
if (/^https?:\/\//i.test(token)) return false;
|
|
2695
3037
|
if (/^\d+$/.test(token)) return false;
|
|
@@ -2716,20 +3058,24 @@ function escapeRegExp(value) {
|
|
|
2716
3058
|
}
|
|
2717
3059
|
export {
|
|
2718
3060
|
AUTOPILOT_DEFAULTS,
|
|
3061
|
+
ActivationSchema,
|
|
2719
3062
|
AnchorSchema,
|
|
2720
3063
|
BRIEFING_MARKER_TTL_MS,
|
|
2721
3064
|
BRIEFING_PRESET_DEFAULTS,
|
|
2722
3065
|
CHARS_PER_TOKEN,
|
|
2723
3066
|
CODE_MAP_FILE,
|
|
3067
|
+
CODE_STOPWORDS,
|
|
2724
3068
|
CONFIG_FILE,
|
|
2725
3069
|
CrossRepoProvenanceSchema,
|
|
2726
3070
|
DECAY_DAYS,
|
|
2727
3071
|
DEFAULT_AUTO_PROMOTE_RULE,
|
|
2728
3072
|
DEFAULT_CONFIDENCE_THRESHOLDS,
|
|
2729
3073
|
DEFAULT_CONFIG,
|
|
3074
|
+
DEFAULT_DORMANT_DAYS,
|
|
2730
3075
|
GUESSABLE_THRESHOLD,
|
|
2731
3076
|
HAIVE_DIR,
|
|
2732
3077
|
MEMORIES_DIR,
|
|
3078
|
+
MIN_WORD_LEN,
|
|
2733
3079
|
MemoryFrontmatterSchema,
|
|
2734
3080
|
MemoryScopeSchema,
|
|
2735
3081
|
MemoryStatusSchema,
|
|
@@ -2743,6 +3089,8 @@ export {
|
|
|
2743
3089
|
USAGE_LOG_DIR,
|
|
2744
3090
|
USAGE_LOG_FILE,
|
|
2745
3091
|
addedLinesFromDiff,
|
|
3092
|
+
aggregateRetrieval,
|
|
3093
|
+
aggregateSensors,
|
|
2746
3094
|
aggregateUsage,
|
|
2747
3095
|
allocateBudget,
|
|
2748
3096
|
antiPatternGateParams,
|
|
@@ -2751,19 +3099,26 @@ export {
|
|
|
2751
3099
|
briefingMarkerPath,
|
|
2752
3100
|
briefingMarkersDir,
|
|
2753
3101
|
buildCodeMap,
|
|
3102
|
+
buildDocFrequency,
|
|
2754
3103
|
buildFrontmatter,
|
|
3104
|
+
buildReport,
|
|
2755
3105
|
bumpRead,
|
|
2756
3106
|
codeMapPath,
|
|
2757
3107
|
collectTimelineEntries,
|
|
3108
|
+
compareImpact,
|
|
2758
3109
|
compileRegexSensor,
|
|
3110
|
+
computeImpact,
|
|
2759
3111
|
configPath,
|
|
2760
3112
|
contractLockPath,
|
|
2761
3113
|
deriveConfidence,
|
|
2762
3114
|
diffContract,
|
|
3115
|
+
diffHasDistinctiveOverlap,
|
|
3116
|
+
distinctiveCap,
|
|
2763
3117
|
emptyUsage,
|
|
2764
3118
|
emptyUsageIndex,
|
|
2765
3119
|
enforcementDir,
|
|
2766
3120
|
estimateTokens,
|
|
3121
|
+
evaluateSkillActivation,
|
|
2767
3122
|
extractActionsBriefBody,
|
|
2768
3123
|
extractSnippet,
|
|
2769
3124
|
findLexicalConflictPairs,
|
|
@@ -2776,10 +3131,13 @@ export {
|
|
|
2776
3131
|
inferModulesFromPaths,
|
|
2777
3132
|
isAutoPromoteEligible,
|
|
2778
3133
|
isDecaying,
|
|
3134
|
+
isDistinctiveToken,
|
|
2779
3135
|
isFreshIsoDate,
|
|
2780
3136
|
isGlobPath,
|
|
2781
3137
|
isLikelyGuessable,
|
|
2782
3138
|
isRetiredMemory,
|
|
3139
|
+
isSkill,
|
|
3140
|
+
isSkillSuppressed,
|
|
2783
3141
|
isStackPackSeed,
|
|
2784
3142
|
listMarkdownFilesRecursive,
|
|
2785
3143
|
literalMatchesAllTokens,
|
|
@@ -2794,6 +3152,7 @@ export {
|
|
|
2794
3152
|
memoryMatchesAnchorPaths,
|
|
2795
3153
|
newMemoryId,
|
|
2796
3154
|
normalizeSessionId,
|
|
3155
|
+
overallScore,
|
|
2797
3156
|
parseMemory,
|
|
2798
3157
|
parseSince,
|
|
2799
3158
|
pathsOverlap,
|
|
@@ -2804,6 +3163,7 @@ export {
|
|
|
2804
3163
|
readRecentBriefingMarker,
|
|
2805
3164
|
readRuntimeJournalTail,
|
|
2806
3165
|
readUsageEvents,
|
|
3166
|
+
recordApplied,
|
|
2807
3167
|
recordRejection,
|
|
2808
3168
|
relPathFrom,
|
|
2809
3169
|
resolveBriefingBudget,
|
|
@@ -2817,6 +3177,8 @@ export {
|
|
|
2817
3177
|
saveCodeMap,
|
|
2818
3178
|
saveConfig,
|
|
2819
3179
|
saveUsageIndex,
|
|
3180
|
+
scoreRetrievalCase,
|
|
3181
|
+
scoreSensorCase,
|
|
2820
3182
|
sensorAppliesToPath,
|
|
2821
3183
|
sensorTargetsFromDiff,
|
|
2822
3184
|
serializeMemory,
|
|
@@ -2825,7 +3187,11 @@ export {
|
|
|
2825
3187
|
stripPrivate,
|
|
2826
3188
|
suggestSensorFromMemory,
|
|
2827
3189
|
suggestTopicKey,
|
|
3190
|
+
summarizeImpact,
|
|
3191
|
+
synthesizeSelfEvalCases,
|
|
3192
|
+
titleFromBody,
|
|
2828
3193
|
tokenizeQuery,
|
|
3194
|
+
tokenizeWords,
|
|
2829
3195
|
trackDependencies,
|
|
2830
3196
|
trackReads,
|
|
2831
3197
|
truncateToTokens,
|