@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.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] ?? emptyUsage();
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] ?? emptyUsage();
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] ?? emptyUsage();
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 MS_PER_DAY = 24 * 60 * 60 * 1e3;
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()) / MS_PER_DAY;
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 (!isDistinctiveToken(key, true) || isBoringValue(value)) continue;
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 (!isDistinctiveToken(key, true) || isBoringValue(value)) continue;
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 (!isDistinctiveToken(token, isCodeLike)) continue;
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 isDistinctiveToken(token, isCodeLike) {
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,