@rayul/kordis 0.15.1 → 0.15.2
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/NOTICE +1 -1
- package/assets/AGENTS.md +108 -0
- package/assets/MEMGINEERING.md +3 -1
- package/assets/kordis-publishing/SKILL.md +18 -11
- package/assets/kordis-recommend/SKILL.md +2 -1
- package/assets/memgineering-recall/SKILL.md +21 -4
- package/assets/memgineering-rules/SKILL.md +59 -15
- package/assets/memgineering-setup/SKILL.md +61 -13
- package/assets/memgineering-writing/SKILL.md +68 -17
- package/dist/index.js +1065 -106
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1159,12 +1159,17 @@ var init_api = __esm({
|
|
|
1159
1159
|
*/
|
|
1160
1160
|
content: z11.string().min(50).max(1e5),
|
|
1161
1161
|
/**
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1162
|
+
* Accepted and ignored. core-api stores the title, description and type it
|
|
1163
|
+
* reads from the frontmatter of `content`, which must carry all three; these
|
|
1164
|
+
* three fields change nothing (`kordis push --type` sends `type` here).
|
|
1164
1165
|
*/
|
|
1165
1166
|
title: z11.string().min(1).max(200).optional(),
|
|
1166
1167
|
description: z11.string().min(1).max(2048).optional(),
|
|
1167
1168
|
type: HarnessTypeSchema.optional(),
|
|
1169
|
+
/**
|
|
1170
|
+
* A new package is published under this slug instead of the one derived from
|
|
1171
|
+
* the frontmatter title. An update keeps the slug of the package it updates.
|
|
1172
|
+
*/
|
|
1168
1173
|
slug: SlugSchema.optional(),
|
|
1169
1174
|
/**
|
|
1170
1175
|
* When updating, the target full_slug. Omitted for new packages (server
|
|
@@ -2443,13 +2448,17 @@ var init_sections = __esm({
|
|
|
2443
2448
|
|
|
2444
2449
|
// ../../packages/memory-engine/src/schema.ts
|
|
2445
2450
|
import { z as z22 } from "zod";
|
|
2446
|
-
|
|
2451
|
+
function isGlobalScope(scope) {
|
|
2452
|
+
return scope != null && scope.trim().toLowerCase() === GLOBAL_SCOPE;
|
|
2453
|
+
}
|
|
2454
|
+
var MappingModeSchema, ScopeSourceSchema, SCOPE_LIMIT, GLOBAL_SCOPE, TELEMETRY_ERROR_KINDS, TELEMETRY_MESSAGE_LIMIT, TelemetryErrorPayloadSchema2, ProvenanceSchema, MemoryStatusSchema, ClaimConfidenceSchema, MemoryKindSchema, ClaimSchema, MemorySchema, RelationTypeSchema, RelationSourceSchema, RelationSchema;
|
|
2447
2455
|
var init_schema = __esm({
|
|
2448
2456
|
"../../packages/memory-engine/src/schema.ts"() {
|
|
2449
2457
|
"use strict";
|
|
2450
2458
|
MappingModeSchema = z22.enum(["explicit", "heuristic"]);
|
|
2451
2459
|
ScopeSourceSchema = z22.enum(["explicit", "path", "none"]);
|
|
2452
2460
|
SCOPE_LIMIT = 128;
|
|
2461
|
+
GLOBAL_SCOPE = "global";
|
|
2453
2462
|
TELEMETRY_ERROR_KINDS = [
|
|
2454
2463
|
"network_unreachable",
|
|
2455
2464
|
"server_error",
|
|
@@ -2529,6 +2538,26 @@ var init_schema = __esm({
|
|
|
2529
2538
|
scope: z22.string().min(1).nullable(),
|
|
2530
2539
|
/** Id of the claim that is current for this memory, when one is declared. */
|
|
2531
2540
|
current_claim: z22.string().min(1).nullable(),
|
|
2541
|
+
/**
|
|
2542
|
+
* The end date the NOTE declares, for the notes that state no claim.
|
|
2543
|
+
*
|
|
2544
|
+
* `valid_until` lived only on `Claim`, and the mapper mints a claim only for
|
|
2545
|
+
* a note carrying a `claim:` key — which `remember` has never written. So on
|
|
2546
|
+
* a real brain most notes could not carry an end date that anything read:
|
|
2547
|
+
* sampled six binding rules on a production brain and four had no claim at
|
|
2548
|
+
* all, the two that did having been through `revise`. A date in the
|
|
2549
|
+
* frontmatter of the other four was simply ignored.
|
|
2550
|
+
*
|
|
2551
|
+
* Optional rather than nullable, like `kind` and `binding` above and for the
|
|
2552
|
+
* same reason: a note written before this existed must map to exactly the
|
|
2553
|
+
* `Memory` it always did, or the regeneration test's byte comparison rewrites
|
|
2554
|
+
* every cache in existence on upgrade.
|
|
2555
|
+
*
|
|
2556
|
+
* The claim's copy WINS where both exist — it is the more specific statement,
|
|
2557
|
+
* and a note whose conclusion carries its own dates is saying something about
|
|
2558
|
+
* that conclusion rather than about the file.
|
|
2559
|
+
*/
|
|
2560
|
+
valid_until: z22.string().min(1).optional(),
|
|
2532
2561
|
status: MemoryStatusSchema,
|
|
2533
2562
|
/**
|
|
2534
2563
|
* Whether this memory binds what an agent does, rather than informing it.
|
|
@@ -2610,6 +2639,104 @@ var init_schema = __esm({
|
|
|
2610
2639
|
}
|
|
2611
2640
|
});
|
|
2612
2641
|
|
|
2642
|
+
// ../../packages/memory-engine/src/layout.ts
|
|
2643
|
+
var OBSERVATIONS_DIR, DERIVED_DIR, DERIVED_BLUEPRINT;
|
|
2644
|
+
var init_layout = __esm({
|
|
2645
|
+
"../../packages/memory-engine/src/layout.ts"() {
|
|
2646
|
+
"use strict";
|
|
2647
|
+
OBSERVATIONS_DIR = "_observations";
|
|
2648
|
+
DERIVED_DIR = "_derived";
|
|
2649
|
+
DERIVED_BLUEPRINT = "_blueprint.json";
|
|
2650
|
+
}
|
|
2651
|
+
});
|
|
2652
|
+
|
|
2653
|
+
// ../../packages/memory-engine/src/rule-budget.ts
|
|
2654
|
+
function ruleLane(scope, project) {
|
|
2655
|
+
if (scope == null || scope.trim() === "" || isGlobalScope(scope)) return "global";
|
|
2656
|
+
if (project === null) return "elsewhere";
|
|
2657
|
+
return scope.trim().toLowerCase() === project.trim().toLowerCase() ? "project" : "elsewhere";
|
|
2658
|
+
}
|
|
2659
|
+
function declaredScopeOf(memory) {
|
|
2660
|
+
return memory.provenance.scopeSource === "explicit" ? memory.scope : null;
|
|
2661
|
+
}
|
|
2662
|
+
function splitRuleBudget(ranked, scopeOf, project, budget = DEFAULT_RULE_BUDGET) {
|
|
2663
|
+
const globalLane = [];
|
|
2664
|
+
const projectLane = [];
|
|
2665
|
+
const elsewhere = [];
|
|
2666
|
+
for (const item of ranked) {
|
|
2667
|
+
const lane = ruleLane(scopeOf(item), project);
|
|
2668
|
+
if (lane === "global") globalLane.push(item);
|
|
2669
|
+
else if (lane === "project") projectLane.push(item);
|
|
2670
|
+
else elsewhere.push(item);
|
|
2671
|
+
}
|
|
2672
|
+
const total = budget.global + budget.project;
|
|
2673
|
+
const globalRoom = Math.max(budget.global, total - Math.min(projectLane.length, budget.project));
|
|
2674
|
+
const projectRoom = Math.max(budget.project, total - Math.min(globalLane.length, budget.global));
|
|
2675
|
+
return {
|
|
2676
|
+
global: globalLane.slice(0, globalRoom),
|
|
2677
|
+
project: projectLane.slice(0, projectRoom),
|
|
2678
|
+
elsewhere,
|
|
2679
|
+
// Everything either budget COULD have shown, so "5 of 12" is honest about
|
|
2680
|
+
// the cap without counting another project's rules as things withheld.
|
|
2681
|
+
eligible: globalLane.length + projectLane.length
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
var DEFAULT_RULE_BUDGET;
|
|
2685
|
+
var init_rule_budget = __esm({
|
|
2686
|
+
"../../packages/memory-engine/src/rule-budget.ts"() {
|
|
2687
|
+
"use strict";
|
|
2688
|
+
init_schema();
|
|
2689
|
+
DEFAULT_RULE_BUDGET = { global: 5, project: 5 };
|
|
2690
|
+
}
|
|
2691
|
+
});
|
|
2692
|
+
|
|
2693
|
+
// ../../packages/memory-engine/src/rule-text.ts
|
|
2694
|
+
function ruleTextOf(entry) {
|
|
2695
|
+
const intro = (entry.chunks ?? []).find((chunk) => chunk.label === null)?.text.trim();
|
|
2696
|
+
if (intro !== void 0 && intro !== "") return intro;
|
|
2697
|
+
return entry.memory.summary ?? entry.memory.title;
|
|
2698
|
+
}
|
|
2699
|
+
function ruleWidthFor(count) {
|
|
2700
|
+
if (count <= 0) return RULE_WIDTH_MIN;
|
|
2701
|
+
const share = Math.floor(RULE_BLOCK_BUDGET / count);
|
|
2702
|
+
return Math.min(RULE_WIDTH_MAX, Math.max(RULE_WIDTH_MIN, share));
|
|
2703
|
+
}
|
|
2704
|
+
function rulePassage(text, max) {
|
|
2705
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
2706
|
+
const chars = [...flat];
|
|
2707
|
+
if (chars.length <= max) return flat;
|
|
2708
|
+
if (max <= 1) return "\u2026";
|
|
2709
|
+
const budget = max - 1;
|
|
2710
|
+
if (budget < 2) return `${chars.slice(0, budget).join("")}\u2026`;
|
|
2711
|
+
const tailBudget = Math.min(budget - 1, Math.max(1, Math.floor(budget * 0.6)));
|
|
2712
|
+
const tail = [...trailingSentences(flat, tailBudget)];
|
|
2713
|
+
const head = chars.slice(0, budget - tail.length).join("").trimEnd();
|
|
2714
|
+
return `${head}\u2026${tail.join("")}`;
|
|
2715
|
+
}
|
|
2716
|
+
function trailingSentences(flat, budget) {
|
|
2717
|
+
const starts = [...flat.matchAll(/[.!?。!?](?=\s)/g)].map(
|
|
2718
|
+
(match) => match.index + match[0].length
|
|
2719
|
+
);
|
|
2720
|
+
let best = null;
|
|
2721
|
+
for (let i = starts.length - 1; i >= 0; i -= 1) {
|
|
2722
|
+
const candidate = flat.slice(starts[i]).trim();
|
|
2723
|
+
if ([...candidate].length > budget) break;
|
|
2724
|
+
if (candidate !== "") best = candidate;
|
|
2725
|
+
}
|
|
2726
|
+
if (best !== null) return best;
|
|
2727
|
+
return [...flat].slice(-budget).join("");
|
|
2728
|
+
}
|
|
2729
|
+
var RULE_WIRE_WIDTH, RULE_WIDTH_MIN, RULE_WIDTH_MAX, RULE_BLOCK_BUDGET;
|
|
2730
|
+
var init_rule_text = __esm({
|
|
2731
|
+
"../../packages/memory-engine/src/rule-text.ts"() {
|
|
2732
|
+
"use strict";
|
|
2733
|
+
RULE_WIRE_WIDTH = 600;
|
|
2734
|
+
RULE_WIDTH_MIN = 200;
|
|
2735
|
+
RULE_WIDTH_MAX = 600;
|
|
2736
|
+
RULE_BLOCK_BUDGET = RULE_WIDTH_MIN * 10;
|
|
2737
|
+
}
|
|
2738
|
+
});
|
|
2739
|
+
|
|
2613
2740
|
// ../../packages/memory-engine/src/boundary.ts
|
|
2614
2741
|
function normalizeForMatch(value) {
|
|
2615
2742
|
return value.normalize("NFC").replace(ZERO_WIDTH, "").replace(WHITESPACE_RUN, " ").trim();
|
|
@@ -2753,8 +2880,8 @@ function scopeFromPath(path2) {
|
|
|
2753
2880
|
return parts.length >= 2 ? parts[parts.length - 2] ?? null : null;
|
|
2754
2881
|
}
|
|
2755
2882
|
function titleFromPath(path2) {
|
|
2756
|
-
const
|
|
2757
|
-
return
|
|
2883
|
+
const base2 = path2.split("/").pop() ?? path2;
|
|
2884
|
+
return base2.replace(/\.[^.]+$/, "") || base2;
|
|
2758
2885
|
}
|
|
2759
2886
|
function h1Of(intro) {
|
|
2760
2887
|
for (const line of intro.split("\n")) {
|
|
@@ -2868,8 +2995,8 @@ function mapNoteToMemory(input) {
|
|
|
2868
2995
|
const ns = explicit ? nsRaw : {};
|
|
2869
2996
|
const id = asString(ns["id"]) ?? path2;
|
|
2870
2997
|
const title = asString(ns["title"]) ?? asString(frontmatter?.["title"]) ?? h1Of(outline.intro) ?? titleFromPath(path2);
|
|
2871
|
-
const
|
|
2872
|
-
const scope =
|
|
2998
|
+
const declaredScope2 = asString(ns["scope"]);
|
|
2999
|
+
const scope = declaredScope2 ?? scopeFromPath(path2);
|
|
2873
3000
|
const summary = asString(ns["summary"]) ?? outline.description ?? firstParagraph(outline.intro) ?? firstSectionParagraph(outline.sections) ?? null;
|
|
2874
3001
|
const memory = {
|
|
2875
3002
|
id,
|
|
@@ -2913,11 +3040,17 @@ function mapNoteToMemory(input) {
|
|
|
2913
3040
|
aliases: asStringArray(ns["aliases"]),
|
|
2914
3041
|
entities: asStringArray(ns["entities"]),
|
|
2915
3042
|
updated_at: asString(ns["updated_at"]) ?? asString(frontmatter?.["updated_at"]),
|
|
3043
|
+
// Carried onto the memory as well as onto the claim below, because a note
|
|
3044
|
+
// that states no claim gets no claim object at all — and `remember` has
|
|
3045
|
+
// never written a `claim:` key, so that is most of a real brain. Written
|
|
3046
|
+
// only when present, so a note without one maps byte-identically to what
|
|
3047
|
+
// it always did.
|
|
3048
|
+
...asString(ns["valid_until"]) === null ? {} : { valid_until: asString(ns["valid_until"]) },
|
|
2916
3049
|
provenance: {
|
|
2917
3050
|
sourcePath: path2,
|
|
2918
3051
|
sourceRevision: revision,
|
|
2919
3052
|
mapping: explicit ? "explicit" : "heuristic",
|
|
2920
|
-
scopeSource:
|
|
3053
|
+
scopeSource: declaredScope2 !== null ? "explicit" : scope === null ? "none" : "path"
|
|
2921
3054
|
}
|
|
2922
3055
|
};
|
|
2923
3056
|
const claims = [];
|
|
@@ -2943,22 +3076,6 @@ function mapNoteToMemory(input) {
|
|
|
2943
3076
|
issues
|
|
2944
3077
|
};
|
|
2945
3078
|
}
|
|
2946
|
-
function isUntouchedBase(path2, content) {
|
|
2947
|
-
if (!/^01_BASE\//.test(path2)) return false;
|
|
2948
|
-
const body = content.replace(/^---\r?\n[\s\S]*?\r?\n---[ \t]*(\r?\n|$)/, "");
|
|
2949
|
-
const lines = body.split(/\r?\n/).map((l) => l.trimEnd());
|
|
2950
|
-
let seenHeading = false;
|
|
2951
|
-
for (const line of lines) {
|
|
2952
|
-
if (line.trim() === "") continue;
|
|
2953
|
-
if (!seenHeading && line.startsWith("# ")) {
|
|
2954
|
-
seenHeading = true;
|
|
2955
|
-
continue;
|
|
2956
|
-
}
|
|
2957
|
-
if (/^-\s*$/.test(line)) continue;
|
|
2958
|
-
if (/^[-*+]\s+\S/.test(line) || /^#{1,6}\s/.test(line)) return false;
|
|
2959
|
-
}
|
|
2960
|
-
return seenHeading;
|
|
2961
|
-
}
|
|
2962
3079
|
var NAMESPACE, isRecord, asString, asStringArray, AUTHORABLE;
|
|
2963
3080
|
var init_markdown_mapping = __esm({
|
|
2964
3081
|
"../../packages/memory-engine/src/markdown-mapping.ts"() {
|
|
@@ -3048,7 +3165,7 @@ var init_cache_io = __esm({
|
|
|
3048
3165
|
"../../packages/memory-engine/src/view/cache-io.ts"() {
|
|
3049
3166
|
"use strict";
|
|
3050
3167
|
init_schema();
|
|
3051
|
-
SCHEMA_VERSION =
|
|
3168
|
+
SCHEMA_VERSION = 7;
|
|
3052
3169
|
POLICY_VERSION = 1;
|
|
3053
3170
|
CacheEntrySchema = z23.object({
|
|
3054
3171
|
path: z23.string().min(1),
|
|
@@ -3663,6 +3780,12 @@ function terms(text) {
|
|
|
3663
3780
|
(match) => splitMixedScript(match[0])
|
|
3664
3781
|
);
|
|
3665
3782
|
}
|
|
3783
|
+
function contentTerms(text) {
|
|
3784
|
+
const all = terms(text);
|
|
3785
|
+
if (all.some((t) => HANGUL.test(t))) return all;
|
|
3786
|
+
const content = all.filter((t) => !LATIN_STOPWORDS.has(t));
|
|
3787
|
+
return content.length > 0 ? content : all;
|
|
3788
|
+
}
|
|
3666
3789
|
function indexTerms(text) {
|
|
3667
3790
|
return [...text.normalize("NFC").toLowerCase().matchAll(TOKEN)].flatMap((match) => {
|
|
3668
3791
|
const token = match[0];
|
|
@@ -3735,8 +3858,9 @@ function fieldScore(queryTerms, field, weight, allowLeadingOneSyllable = false)
|
|
|
3735
3858
|
return score;
|
|
3736
3859
|
}
|
|
3737
3860
|
function searchMemories(memories, query) {
|
|
3738
|
-
const q =
|
|
3861
|
+
const q = contentTerms(query);
|
|
3739
3862
|
if (q.length === 0) return [];
|
|
3863
|
+
const scale = terms(query).length;
|
|
3740
3864
|
const scored = [];
|
|
3741
3865
|
for (const memory of memories) {
|
|
3742
3866
|
let score = fieldScore(q, memory.title, WEIGHTS.title, true);
|
|
@@ -3744,13 +3868,13 @@ function searchMemories(memories, query) {
|
|
|
3744
3868
|
for (const entity of memory.entities) score += fieldScore(q, entity, WEIGHTS.entity);
|
|
3745
3869
|
score += fieldScore(q, memory.summary, WEIGHTS.summary);
|
|
3746
3870
|
score += fieldScore(q, memory.scope, WEIGHTS.scope);
|
|
3747
|
-
if (score > 0) scored.push({ memory, score: score /
|
|
3871
|
+
if (score > 0) scored.push({ memory, score: score / scale });
|
|
3748
3872
|
}
|
|
3749
3873
|
return scored.sort(
|
|
3750
3874
|
(a, b) => b.score !== a.score ? b.score - a.score : a.memory.id < b.memory.id ? -1 : 1
|
|
3751
3875
|
);
|
|
3752
3876
|
}
|
|
3753
|
-
var WEIGHTS, TOKEN, COMPONENT_SEPARATOR, HAS_COMPONENT_SEPARATOR, LATIN_HANGUL_BOUNDARY, SUBSTRING_MIN, PARTICLES, HANGUL, ONE_SYLLABLE_TOPIC_TERMS;
|
|
3877
|
+
var WEIGHTS, TOKEN, COMPONENT_SEPARATOR, HAS_COMPONENT_SEPARATOR, LATIN_HANGUL_BOUNDARY, LATIN_STOPWORDS, SUBSTRING_MIN, PARTICLES, HANGUL, ONE_SYLLABLE_TOPIC_TERMS;
|
|
3754
3878
|
var init_search = __esm({
|
|
3755
3879
|
"../../packages/memory-engine/src/recall/search.ts"() {
|
|
3756
3880
|
"use strict";
|
|
@@ -3759,6 +3883,120 @@ var init_search = __esm({
|
|
|
3759
3883
|
COMPONENT_SEPARATOR = /[._/-]+/u;
|
|
3760
3884
|
HAS_COMPONENT_SEPARATOR = /[._/-]/u;
|
|
3761
3885
|
LATIN_HANGUL_BOUNDARY = new RegExp("(?<=\\p{Script=Latin})(?=\\p{Script=Hangul})|(?<=\\p{Script=Hangul})(?=\\p{Script=Latin})", "u");
|
|
3886
|
+
LATIN_STOPWORDS = /* @__PURE__ */ new Set([
|
|
3887
|
+
// pronouns and possessives
|
|
3888
|
+
"i",
|
|
3889
|
+
"me",
|
|
3890
|
+
"my",
|
|
3891
|
+
"mine",
|
|
3892
|
+
"myself",
|
|
3893
|
+
"we",
|
|
3894
|
+
"us",
|
|
3895
|
+
"our",
|
|
3896
|
+
"ours",
|
|
3897
|
+
"ourselves",
|
|
3898
|
+
"you",
|
|
3899
|
+
"your",
|
|
3900
|
+
"yours",
|
|
3901
|
+
"yourself",
|
|
3902
|
+
"yourselves",
|
|
3903
|
+
"he",
|
|
3904
|
+
"him",
|
|
3905
|
+
"his",
|
|
3906
|
+
"himself",
|
|
3907
|
+
"she",
|
|
3908
|
+
"her",
|
|
3909
|
+
"hers",
|
|
3910
|
+
"herself",
|
|
3911
|
+
"it",
|
|
3912
|
+
"its",
|
|
3913
|
+
"itself",
|
|
3914
|
+
"they",
|
|
3915
|
+
"them",
|
|
3916
|
+
"their",
|
|
3917
|
+
"theirs",
|
|
3918
|
+
"themselves",
|
|
3919
|
+
// determiners
|
|
3920
|
+
"a",
|
|
3921
|
+
"an",
|
|
3922
|
+
"the",
|
|
3923
|
+
"this",
|
|
3924
|
+
"that",
|
|
3925
|
+
"these",
|
|
3926
|
+
"those",
|
|
3927
|
+
"some",
|
|
3928
|
+
"any",
|
|
3929
|
+
"each",
|
|
3930
|
+
"every",
|
|
3931
|
+
// auxiliaries and modals
|
|
3932
|
+
"am",
|
|
3933
|
+
"is",
|
|
3934
|
+
"are",
|
|
3935
|
+
"was",
|
|
3936
|
+
"were",
|
|
3937
|
+
"be",
|
|
3938
|
+
"been",
|
|
3939
|
+
"being",
|
|
3940
|
+
"do",
|
|
3941
|
+
"does",
|
|
3942
|
+
"did",
|
|
3943
|
+
"have",
|
|
3944
|
+
"has",
|
|
3945
|
+
"had",
|
|
3946
|
+
"will",
|
|
3947
|
+
"would",
|
|
3948
|
+
"shall",
|
|
3949
|
+
"should",
|
|
3950
|
+
"can",
|
|
3951
|
+
"could",
|
|
3952
|
+
"may",
|
|
3953
|
+
"might",
|
|
3954
|
+
"must",
|
|
3955
|
+
// question words
|
|
3956
|
+
"what",
|
|
3957
|
+
"which",
|
|
3958
|
+
"who",
|
|
3959
|
+
"whom",
|
|
3960
|
+
"whose",
|
|
3961
|
+
"when",
|
|
3962
|
+
"where",
|
|
3963
|
+
"why",
|
|
3964
|
+
"how",
|
|
3965
|
+
// prepositions
|
|
3966
|
+
"about",
|
|
3967
|
+
"above",
|
|
3968
|
+
"after",
|
|
3969
|
+
"at",
|
|
3970
|
+
"before",
|
|
3971
|
+
"by",
|
|
3972
|
+
"for",
|
|
3973
|
+
"from",
|
|
3974
|
+
"in",
|
|
3975
|
+
"into",
|
|
3976
|
+
"of",
|
|
3977
|
+
"off",
|
|
3978
|
+
"on",
|
|
3979
|
+
"onto",
|
|
3980
|
+
"over",
|
|
3981
|
+
"to",
|
|
3982
|
+
"under",
|
|
3983
|
+
"with",
|
|
3984
|
+
"without",
|
|
3985
|
+
"through",
|
|
3986
|
+
"during",
|
|
3987
|
+
// conjunctions and particles
|
|
3988
|
+
"and",
|
|
3989
|
+
"but",
|
|
3990
|
+
"or",
|
|
3991
|
+
"nor",
|
|
3992
|
+
"so",
|
|
3993
|
+
"if",
|
|
3994
|
+
"then",
|
|
3995
|
+
"than",
|
|
3996
|
+
"as",
|
|
3997
|
+
"there",
|
|
3998
|
+
"here"
|
|
3999
|
+
]);
|
|
3762
4000
|
SUBSTRING_MIN = 2;
|
|
3763
4001
|
PARTICLES = [
|
|
3764
4002
|
"\uC774\uB77C\uB3C4",
|
|
@@ -3909,7 +4147,7 @@ function freshnessOf(memory, claims, now) {
|
|
|
3909
4147
|
if (memory.status === "superseded") return "superseded";
|
|
3910
4148
|
if (memory.status === "retired") return "retired";
|
|
3911
4149
|
const current = claims.find((c2) => c2.id === memory.current_claim) ?? claims[0];
|
|
3912
|
-
const until = current?.valid_until;
|
|
4150
|
+
const until = current?.valid_until ?? memory.valid_until ?? null;
|
|
3913
4151
|
if (until != null) {
|
|
3914
4152
|
const t = Date.parse(until);
|
|
3915
4153
|
if (Number.isFinite(t) && t < now.getTime()) return "expired";
|
|
@@ -3939,7 +4177,23 @@ function recall(entries, query, opts = {}) {
|
|
|
3939
4177
|
(e) => (e.chunks ?? []).map((c2) => ({ memoryId: e.memory.id, label: c2.label, text: c2.text }))
|
|
3940
4178
|
)
|
|
3941
4179
|
).search(queryShape.lexical);
|
|
3942
|
-
const
|
|
4180
|
+
const offeredSemantic = depth === "exact" ? [] : opts.semantic ?? [];
|
|
4181
|
+
const reachedByWords = /* @__PURE__ */ new Set([
|
|
4182
|
+
...cardHits.map((hit) => hit.memory.id),
|
|
4183
|
+
...chunkHits.map((hit) => hit.memoryId)
|
|
4184
|
+
]);
|
|
4185
|
+
const floor = opts.meaningFloor;
|
|
4186
|
+
const bestSimilarity = offeredSemantic.reduce(
|
|
4187
|
+
(best, hit) => Math.max(best, Math.min(1, Math.max(0, hit.similarity))),
|
|
4188
|
+
0
|
|
4189
|
+
);
|
|
4190
|
+
const semanticHits = floor === void 0 ? offeredSemantic : offeredSemantic.filter((hit) => {
|
|
4191
|
+
if (reachedByWords.has(hit.id)) return true;
|
|
4192
|
+
const s = Math.min(1, Math.max(0, hit.similarity));
|
|
4193
|
+
if (floor.absolute !== void 0 && s < floor.absolute) return false;
|
|
4194
|
+
if (floor.gap !== void 0 && bestSimilarity - s > floor.gap) return false;
|
|
4195
|
+
return true;
|
|
4196
|
+
});
|
|
3943
4197
|
const scoreById = /* @__PURE__ */ new Map();
|
|
3944
4198
|
for (const hit of cardHits) scoreById.set(hit.memory.id, hit.score);
|
|
3945
4199
|
for (const hit of chunkHits) {
|
|
@@ -3949,6 +4203,14 @@ function recall(entries, query, opts = {}) {
|
|
|
3949
4203
|
const similarity = Math.min(1, Math.max(0, hit.similarity));
|
|
3950
4204
|
scoreById.set(hit.id, (scoreById.get(hit.id) ?? 0) + similarity * SEMANTIC_WEIGHT);
|
|
3951
4205
|
}
|
|
4206
|
+
const wordIds = reachedByWords;
|
|
4207
|
+
const meaningIds = new Set(semanticHits.map((hit) => hit.id));
|
|
4208
|
+
const matchedOf = (id) => {
|
|
4209
|
+
if (opts.semantic === void 0 || depth === "exact") return void 0;
|
|
4210
|
+
const words = wordIds.has(id);
|
|
4211
|
+
const meaning = meaningIds.has(id);
|
|
4212
|
+
return words && meaning ? "both" : words ? "words" : meaning ? "meaning" : void 0;
|
|
4213
|
+
};
|
|
3952
4214
|
const memoryById = new Map(allMemories.map((m) => [m.id, m]));
|
|
3953
4215
|
const hits = [...scoreById.entries()].flatMap(([id, score]) => {
|
|
3954
4216
|
const memory = memoryById.get(id);
|
|
@@ -4049,7 +4311,11 @@ function recall(entries, query, opts = {}) {
|
|
|
4049
4311
|
type: memory.type,
|
|
4050
4312
|
// The handle IS the progressive part. No claim text here, by
|
|
4051
4313
|
// construction rather than by remembering to strip it.
|
|
4052
|
-
detail_handle: `recall://${memory.id}
|
|
4314
|
+
detail_handle: `recall://${memory.id}`,
|
|
4315
|
+
...(() => {
|
|
4316
|
+
const matched = matchedOf(memory.id);
|
|
4317
|
+
return matched === void 0 ? {} : { matched };
|
|
4318
|
+
})()
|
|
4053
4319
|
};
|
|
4054
4320
|
}
|
|
4055
4321
|
}
|
|
@@ -4080,7 +4346,7 @@ function resolveDetail(entries, handle) {
|
|
|
4080
4346
|
const entry = entries.find((e) => e.memory.id === id);
|
|
4081
4347
|
return entry ? { memory: entry.memory, claims: entry.claims, relations: entry.relations } : null;
|
|
4082
4348
|
}
|
|
4083
|
-
var RECALL_DEPTHS, RecallOptionError, SEMANTIC_CANDIDATES, DEFAULTS, BODY_WEIGHT, SEMANTIC_WEIGHT, BINDING_BOOST, KIND_BOOST, DECISION_NOUNS, DECISION_CONTEXT, DECISION_FILLERS, CURRENCY_RANK, WIDEST_ESTIMATE;
|
|
4349
|
+
var MEANING_ONLY_NOTE, RECALL_DEPTHS, RecallOptionError, SEMANTIC_CANDIDATES, DEFAULTS, BODY_WEIGHT, SEMANTIC_WEIGHT, BINDING_BOOST, KIND_BOOST, DECISION_NOUNS, DECISION_CONTEXT, DECISION_FILLERS, CURRENCY_RANK, WIDEST_ESTIMATE;
|
|
4084
4350
|
var init_planner = __esm({
|
|
4085
4351
|
"../../packages/memory-engine/src/recall/planner.ts"() {
|
|
4086
4352
|
"use strict";
|
|
@@ -4089,6 +4355,7 @@ var init_planner = __esm({
|
|
|
4089
4355
|
init_conflicts();
|
|
4090
4356
|
init_chunks();
|
|
4091
4357
|
init_search();
|
|
4358
|
+
MEANING_ONLY_NOTE = "matched by meaning only \u2014 none of the question\u2019s words are in this note";
|
|
4092
4359
|
RECALL_DEPTHS = ["exact", "standard"];
|
|
4093
4360
|
RecallOptionError = class extends Error {
|
|
4094
4361
|
hint;
|
|
@@ -4175,18 +4442,164 @@ var init_planner = __esm({
|
|
|
4175
4442
|
}
|
|
4176
4443
|
});
|
|
4177
4444
|
|
|
4445
|
+
// ../../packages/memory-engine/src/note-body.ts
|
|
4446
|
+
function bodyOf(content) {
|
|
4447
|
+
const stripped = content.startsWith(BOM) ? content.slice(BOM.length) : content;
|
|
4448
|
+
const fence2 = FENCE.exec(stripped);
|
|
4449
|
+
return fence2 ? stripped.slice(fence2[0].length) : stripped;
|
|
4450
|
+
}
|
|
4451
|
+
var BOM, FENCE;
|
|
4452
|
+
var init_note_body = __esm({
|
|
4453
|
+
"../../packages/memory-engine/src/note-body.ts"() {
|
|
4454
|
+
"use strict";
|
|
4455
|
+
BOM = String.fromCharCode(65279);
|
|
4456
|
+
FENCE = /^---[ \t]*\r?\n[\s\S]*?\r?\n---[ \t]*(\r?\n|$)/;
|
|
4457
|
+
}
|
|
4458
|
+
});
|
|
4459
|
+
|
|
4460
|
+
// ../../packages/memory-engine/src/base-templates.ts
|
|
4461
|
+
function base(id, title, summary, body) {
|
|
4462
|
+
return [
|
|
4463
|
+
"---",
|
|
4464
|
+
"memgineering:",
|
|
4465
|
+
` id: ${id}`,
|
|
4466
|
+
` title: ${title}`,
|
|
4467
|
+
` summary: ${summary}`,
|
|
4468
|
+
" scope: base",
|
|
4469
|
+
"---",
|
|
4470
|
+
"",
|
|
4471
|
+
`# ${title}`,
|
|
4472
|
+
"",
|
|
4473
|
+
body,
|
|
4474
|
+
""
|
|
4475
|
+
].join("\n");
|
|
4476
|
+
}
|
|
4477
|
+
function ownEntry(record, key2) {
|
|
4478
|
+
return Object.hasOwn(record, key2) ? record[key2] : void 0;
|
|
4479
|
+
}
|
|
4480
|
+
function wordingsFor(path2) {
|
|
4481
|
+
const current = ownEntry(BASE_TEMPLATES, path2);
|
|
4482
|
+
const retired = ownEntry(RETIRED_BASE_TEMPLATES, path2) ?? [];
|
|
4483
|
+
return current === void 0 ? retired : [current, ...retired];
|
|
4484
|
+
}
|
|
4485
|
+
function isExactUntouchedBase(path2, content) {
|
|
4486
|
+
const saved = asSaved(content);
|
|
4487
|
+
return wordingsFor(path2).some((t) => asSaved(t) === saved);
|
|
4488
|
+
}
|
|
4489
|
+
function isTemplateBody(path2, content) {
|
|
4490
|
+
const lines = bodyLines(content).join("\n");
|
|
4491
|
+
return wordingsFor(path2).some((t) => bodyLines(t).join("\n") === lines);
|
|
4492
|
+
}
|
|
4493
|
+
function isUnwrittenBody(path2, content) {
|
|
4494
|
+
if (isTemplateBody(path2, content)) return true;
|
|
4495
|
+
const [first, ...rest] = bodyLines(content);
|
|
4496
|
+
if (first === void 0) return false;
|
|
4497
|
+
const headings = wordingsFor(path2).map((t) => bodyLines(t)[0]);
|
|
4498
|
+
return headings.includes(first) && rest.every((line) => /^-\s*$/.test(line));
|
|
4499
|
+
}
|
|
4500
|
+
var BASE_TEMPLATES, RETIRED_BASE_TEMPLATES, BOM2, asSaved, bodyLines;
|
|
4501
|
+
var init_base_templates = __esm({
|
|
4502
|
+
"../../packages/memory-engine/src/base-templates.ts"() {
|
|
4503
|
+
"use strict";
|
|
4504
|
+
init_note_body();
|
|
4505
|
+
BASE_TEMPLATES = {
|
|
4506
|
+
"01_BASE/CRITICAL_FACTS.md": base(
|
|
4507
|
+
"critical-facts",
|
|
4508
|
+
"Critical facts",
|
|
4509
|
+
"The few things that must never be wrong.",
|
|
4510
|
+
[
|
|
4511
|
+
"Keep this short enough to read every session. Anything that can be",
|
|
4512
|
+
"looked up when needed belongs in a note instead.",
|
|
4513
|
+
"",
|
|
4514
|
+
"- "
|
|
4515
|
+
].join("\n")
|
|
4516
|
+
),
|
|
4517
|
+
"01_BASE/USER.md": base(
|
|
4518
|
+
"user",
|
|
4519
|
+
"About me",
|
|
4520
|
+
"Who I am and what context I work in.",
|
|
4521
|
+
[
|
|
4522
|
+
"Background, role, what you are working on, what an agent should assume",
|
|
4523
|
+
"you already know.",
|
|
4524
|
+
"",
|
|
4525
|
+
"- "
|
|
4526
|
+
].join("\n")
|
|
4527
|
+
),
|
|
4528
|
+
"01_BASE/PREFERENCES.md": base(
|
|
4529
|
+
"preferences",
|
|
4530
|
+
"Preferences",
|
|
4531
|
+
"How I like answers, code and decisions handled.",
|
|
4532
|
+
["Style, verbosity, how much to check in, how you like code written.", "", "- "].join("\n")
|
|
4533
|
+
),
|
|
4534
|
+
"01_BASE/BOUNDARIES.md": base(
|
|
4535
|
+
"boundaries",
|
|
4536
|
+
"Boundaries",
|
|
4537
|
+
"What an agent must not do without asking me first.",
|
|
4538
|
+
[
|
|
4539
|
+
"Privacy, spending, anything irreversible, anything that leaves this",
|
|
4540
|
+
"machine. Be specific \u2014 a boundary that has to be interpreted is one",
|
|
4541
|
+
"that will be interpreted generously.",
|
|
4542
|
+
"",
|
|
4543
|
+
"Storage boundaries belong here too: topics you never want written into",
|
|
4544
|
+
"this brain \u2014 health, beliefs, relationships, anything you name. An",
|
|
4545
|
+
"agent checks this file before it records anything.",
|
|
4546
|
+
"",
|
|
4547
|
+
"- "
|
|
4548
|
+
].join("\n")
|
|
4549
|
+
),
|
|
4550
|
+
"01_BASE/TOOLING.md": base(
|
|
4551
|
+
"tooling",
|
|
4552
|
+
"Tooling",
|
|
4553
|
+
"The tools, machines and commands I actually use.",
|
|
4554
|
+
[
|
|
4555
|
+
"Editors, languages, deploy commands, where things run. Enough that an",
|
|
4556
|
+
"agent does not have to guess or discover it again each time.",
|
|
4557
|
+
"",
|
|
4558
|
+
"- "
|
|
4559
|
+
].join("\n")
|
|
4560
|
+
)
|
|
4561
|
+
};
|
|
4562
|
+
RETIRED_BASE_TEMPLATES = {
|
|
4563
|
+
// Retired 0.11.1, when the prompt grew a storage-boundary invitation.
|
|
4564
|
+
"01_BASE/BOUNDARIES.md": [
|
|
4565
|
+
[
|
|
4566
|
+
"---",
|
|
4567
|
+
"memgineering:",
|
|
4568
|
+
" id: boundaries",
|
|
4569
|
+
" title: Boundaries",
|
|
4570
|
+
" summary: What an agent must not do without asking me first.",
|
|
4571
|
+
" scope: base",
|
|
4572
|
+
"---",
|
|
4573
|
+
"",
|
|
4574
|
+
"# Boundaries",
|
|
4575
|
+
"",
|
|
4576
|
+
"Privacy, spending, anything irreversible, anything that leaves this",
|
|
4577
|
+
"machine. Be specific \u2014 a boundary that has to be interpreted is one",
|
|
4578
|
+
"that will be interpreted generously.",
|
|
4579
|
+
"",
|
|
4580
|
+
"- ",
|
|
4581
|
+
""
|
|
4582
|
+
].join("\n")
|
|
4583
|
+
]
|
|
4584
|
+
};
|
|
4585
|
+
BOM2 = String.fromCharCode(65279);
|
|
4586
|
+
asSaved = (text) => (text.startsWith(BOM2) ? text.slice(BOM2.length) : text).replace(/\r\n/g, "\n").trimEnd();
|
|
4587
|
+
bodyLines = (content) => bodyOf(content).split("\n").map((line) => line.trimEnd()).filter((line) => line.trim() !== "");
|
|
4588
|
+
}
|
|
4589
|
+
});
|
|
4590
|
+
|
|
4178
4591
|
// ../../packages/memory-engine/src/recall/semantic.ts
|
|
4179
|
-
function withoutUntouchedBase(hits, contentById) {
|
|
4592
|
+
function withoutUntouchedBase(hits, contentById, isTemplate = isExactUntouchedBase) {
|
|
4180
4593
|
return hits.filter((hit) => {
|
|
4181
4594
|
const note = contentById.get(hit.id);
|
|
4182
|
-
return note === void 0 ? true : !
|
|
4595
|
+
return note === void 0 ? true : !isTemplate(note.path, note.content);
|
|
4183
4596
|
});
|
|
4184
4597
|
}
|
|
4185
4598
|
var SEMANTIC_FIELDS;
|
|
4186
4599
|
var init_semantic = __esm({
|
|
4187
4600
|
"../../packages/memory-engine/src/recall/semantic.ts"() {
|
|
4188
4601
|
"use strict";
|
|
4189
|
-
|
|
4602
|
+
init_base_templates();
|
|
4190
4603
|
SEMANTIC_FIELDS = {
|
|
4191
4604
|
/** `used` or `skipped`. Always present on a server that has this at all. */
|
|
4192
4605
|
state: "semantic",
|
|
@@ -4200,6 +4613,103 @@ var init_semantic = __esm({
|
|
|
4200
4613
|
}
|
|
4201
4614
|
});
|
|
4202
4615
|
|
|
4616
|
+
// ../../packages/memory-engine/src/recall/unfilled.ts
|
|
4617
|
+
function markUnfilled(cards, contentById, slots, inConflict = /* @__PURE__ */ new Set()) {
|
|
4618
|
+
const kept = [];
|
|
4619
|
+
const withheld = [];
|
|
4620
|
+
let templates = 0;
|
|
4621
|
+
for (const card of cards) {
|
|
4622
|
+
const note = contentById.get(card.id);
|
|
4623
|
+
const unfilled = note !== void 0 && isExactUntouchedBase(note.path, note.content);
|
|
4624
|
+
if (unfilled && slots !== void 0 && !inConflict.has(card.id) && ++templates > slots) {
|
|
4625
|
+
withheld.push(card.id);
|
|
4626
|
+
continue;
|
|
4627
|
+
}
|
|
4628
|
+
kept.push({ ...card, unfilled });
|
|
4629
|
+
}
|
|
4630
|
+
return { cards: kept, withheld };
|
|
4631
|
+
}
|
|
4632
|
+
var UNFILLED_FIELDS;
|
|
4633
|
+
var init_unfilled = __esm({
|
|
4634
|
+
"../../packages/memory-engine/src/recall/unfilled.ts"() {
|
|
4635
|
+
"use strict";
|
|
4636
|
+
init_base_templates();
|
|
4637
|
+
UNFILLED_FIELDS = {
|
|
4638
|
+
/** On every card from a server that has this: still the starter file, nothing written in it. */
|
|
4639
|
+
card: "unfilled",
|
|
4640
|
+
/**
|
|
4641
|
+
* In the request: how many such cards the caller will take. Absent means no
|
|
4642
|
+
* cap, so a client older than the field gets the whole ranking it always got —
|
|
4643
|
+
* the same boundary `budget` draws: the client states the capability.
|
|
4644
|
+
*/
|
|
4645
|
+
slots: "template_slots",
|
|
4646
|
+
/** In the response, only when the cap left something out: how many. */
|
|
4647
|
+
withheld: "templates_withheld"
|
|
4648
|
+
};
|
|
4649
|
+
}
|
|
4650
|
+
});
|
|
4651
|
+
|
|
4652
|
+
// ../../packages/memory-engine/src/setup-progress.ts
|
|
4653
|
+
var SETUP_PROGRESS_CODES;
|
|
4654
|
+
var init_setup_progress = __esm({
|
|
4655
|
+
"../../packages/memory-engine/src/setup-progress.ts"() {
|
|
4656
|
+
"use strict";
|
|
4657
|
+
SETUP_PROGRESS_CODES = [
|
|
4658
|
+
/** Installing the guidance and settings. */
|
|
4659
|
+
"writing_config",
|
|
4660
|
+
/** Uploading the chosen folder's notes. */
|
|
4661
|
+
"uploading",
|
|
4662
|
+
/** An upload chosen on the screen, held until somebody at the terminal checks the account. */
|
|
4663
|
+
"upload_waits_for_check",
|
|
4664
|
+
/** Finished. */
|
|
4665
|
+
"done",
|
|
4666
|
+
/** This machine is signed in to a different account; nothing was changed. */
|
|
4667
|
+
"different_account",
|
|
4668
|
+
/** Failed for another reason; `detail` says which. */
|
|
4669
|
+
"failed"
|
|
4670
|
+
];
|
|
4671
|
+
}
|
|
4672
|
+
});
|
|
4673
|
+
|
|
4674
|
+
// ../../packages/memory-engine/src/recall/query-prefix.ts
|
|
4675
|
+
var QUERY_EMBEDDING_PREFIX;
|
|
4676
|
+
var init_query_prefix = __esm({
|
|
4677
|
+
"../../packages/memory-engine/src/recall/query-prefix.ts"() {
|
|
4678
|
+
"use strict";
|
|
4679
|
+
QUERY_EMBEDDING_PREFIX = "task: search result | query: ";
|
|
4680
|
+
}
|
|
4681
|
+
});
|
|
4682
|
+
|
|
4683
|
+
// ../../packages/memory-engine/src/recall/scope-spread.ts
|
|
4684
|
+
function declaredScope(memory) {
|
|
4685
|
+
return memory.provenance?.scopeSource === "explicit" ? memory.scope ?? null : null;
|
|
4686
|
+
}
|
|
4687
|
+
function scopeSpread(returned, brain) {
|
|
4688
|
+
const scoped = returned.filter((s) => typeof s === "string" && s !== "");
|
|
4689
|
+
const distinct = new Set(scoped);
|
|
4690
|
+
if (distinct.size !== 1) return null;
|
|
4691
|
+
const only = [...distinct][0];
|
|
4692
|
+
const others = /* @__PURE__ */ new Set();
|
|
4693
|
+
for (const scope of brain) if (scope && scope !== only) others.add(scope);
|
|
4694
|
+
if (others.size === 0) return null;
|
|
4695
|
+
const sorted = [...others].sort((a, b) => a.localeCompare(b));
|
|
4696
|
+
return {
|
|
4697
|
+
scope: only,
|
|
4698
|
+
cards: scoped.length,
|
|
4699
|
+
of: returned.length,
|
|
4700
|
+
elsewhere: sorted.slice(0, ELSEWHERE_SHOWN),
|
|
4701
|
+
elsewhere_total: sorted.length
|
|
4702
|
+
};
|
|
4703
|
+
}
|
|
4704
|
+
var SCOPE_SPREAD_FIELD, ELSEWHERE_SHOWN;
|
|
4705
|
+
var init_scope_spread = __esm({
|
|
4706
|
+
"../../packages/memory-engine/src/recall/scope-spread.ts"() {
|
|
4707
|
+
"use strict";
|
|
4708
|
+
SCOPE_SPREAD_FIELD = "scope_spread";
|
|
4709
|
+
ELSEWHERE_SHOWN = 5;
|
|
4710
|
+
}
|
|
4711
|
+
});
|
|
4712
|
+
|
|
4203
4713
|
// ../../packages/memory-engine/src/proposal/schema.ts
|
|
4204
4714
|
import { z as z24 } from "zod";
|
|
4205
4715
|
function isLifecycleAction(action) {
|
|
@@ -4208,8 +4718,17 @@ function isLifecycleAction(action) {
|
|
|
4208
4718
|
function isClassifyAction(action) {
|
|
4209
4719
|
return action === "reclassify";
|
|
4210
4720
|
}
|
|
4721
|
+
function isBindingAction(action) {
|
|
4722
|
+
return action === "unbind";
|
|
4723
|
+
}
|
|
4724
|
+
function isScopeAction(action) {
|
|
4725
|
+
return action === "rescope";
|
|
4726
|
+
}
|
|
4727
|
+
function isValidityAction(action) {
|
|
4728
|
+
return action === "expire";
|
|
4729
|
+
}
|
|
4211
4730
|
function carriesNoClaim(action) {
|
|
4212
|
-
return isLifecycleAction(action) || isClassifyAction(action);
|
|
4731
|
+
return isLifecycleAction(action) || isClassifyAction(action) || isBindingAction(action) || isScopeAction(action) || isValidityAction(action);
|
|
4213
4732
|
}
|
|
4214
4733
|
function isAccepted(value) {
|
|
4215
4734
|
return typeof value === "object" && value !== null && value[ACCEPTED] === true;
|
|
@@ -4238,6 +4757,47 @@ var init_schema2 = __esm({
|
|
|
4238
4757
|
"retire",
|
|
4239
4758
|
"unretire",
|
|
4240
4759
|
"reclassify",
|
|
4760
|
+
/**
|
|
4761
|
+
* A memory stops binding. Nothing else about it changes.
|
|
4762
|
+
*
|
|
4763
|
+
* It exists because there was no way to do this without saying something
|
|
4764
|
+
* else. Taking a marking back meant `revise --claim`, which is a verb about
|
|
4765
|
+
* conclusions — so unbinding thirteen rules on a real hosted brain required
|
|
4766
|
+
* restating thirteen conclusions the author had not changed, from text the
|
|
4767
|
+
* CLI hands back TRUNCATED. The person doing it read the note bodies out of
|
|
4768
|
+
* the database to avoid corrupting them, which is not a thing a user can do.
|
|
4769
|
+
*
|
|
4770
|
+
* One direction on purpose. `unbind` that could also bind would be a name
|
|
4771
|
+
* that lies half the time; marking something as a rule is already reachable
|
|
4772
|
+
* (`remember --rule`, or a `revise` that is genuinely saying something new).
|
|
4773
|
+
*/
|
|
4774
|
+
"unbind",
|
|
4775
|
+
/**
|
|
4776
|
+
* Where a memory binds changes. Nothing it SAYS changes.
|
|
4777
|
+
*
|
|
4778
|
+
* `scope` is read by `declaredScopeOf` and decides which of the two rule
|
|
4779
|
+
* budgets a decision is drawn from, so it is the field that answers "does
|
|
4780
|
+
* this bind me here". Nothing could write it. The one live consequence:
|
|
4781
|
+
* folding a project-scoped rule into an unscoped one required superseding
|
|
4782
|
+
* it, which retires the loser — so the rule would have vanished everywhere
|
|
4783
|
+
* except the project it was scoped to.
|
|
4784
|
+
*
|
|
4785
|
+
* The value is a scope NAME, or the reserved word `global`. Never null: see
|
|
4786
|
+
* the refinement below for why "absent" and "widen" must not be the same
|
|
4787
|
+
* value on the wire.
|
|
4788
|
+
*/
|
|
4789
|
+
"rescope",
|
|
4790
|
+
/**
|
|
4791
|
+
* A memory gets an end date. It is not retired, and it still recalls.
|
|
4792
|
+
*
|
|
4793
|
+
* `freshnessOf` has always returned `expired` for a claim whose
|
|
4794
|
+
* `valid_until` has passed, and `CURRENCY_RANK` has always ranked that just
|
|
4795
|
+
* below `current` — read, ranked, and labelled, with nothing able to write
|
|
4796
|
+
* it. A date-stamped fact ("Phase 1 lands by the end of October") therefore
|
|
4797
|
+
* had two options, both wrong: retire it, which says it no longer holds, or
|
|
4798
|
+
* leave it, which says it holds forever.
|
|
4799
|
+
*/
|
|
4800
|
+
"expire",
|
|
4241
4801
|
"ignore"
|
|
4242
4802
|
]);
|
|
4243
4803
|
StorableActionSchema = ProposalActionSchema.exclude(["ignore"]);
|
|
@@ -4397,6 +4957,37 @@ var init_schema2 = __esm({
|
|
|
4397
4957
|
* reclassify is pending — approve, reject, or let it expire first.
|
|
4398
4958
|
*/
|
|
4399
4959
|
proposed_kind: MemoryKindSchema.nullable().default(null),
|
|
4960
|
+
/**
|
|
4961
|
+
* Where `rescope` moves the memory to, and null for everything else.
|
|
4962
|
+
*
|
|
4963
|
+
* NEVER null to mean "everywhere". That was the first design and it is the
|
|
4964
|
+
* one thing this field must not do: "the caller sent no scope" and "the
|
|
4965
|
+
* caller asked to widen this rule" would be the same bytes, so the schema
|
|
4966
|
+
* could not require a scope on a rescope — and a request that LOST the
|
|
4967
|
+
* field, an older client, a hand-built body, a proposal rebuilt from disk,
|
|
4968
|
+
* would silently widen what a rule binds instead of failing.
|
|
4969
|
+
*
|
|
4970
|
+
* `global` is the word instead, and it is not invented here: `GLOBAL_SCOPE`
|
|
4971
|
+
* is already the reserved value a rule write uses to say it holds
|
|
4972
|
+
* everywhere, and `remember` already stores it as no scope at all. So the
|
|
4973
|
+
* widening is spelled, the refinement below can demand it, and the patcher
|
|
4974
|
+
* still writes what the thirty global rules already on a real brain look
|
|
4975
|
+
* like — no key.
|
|
4976
|
+
*
|
|
4977
|
+
* COMPATIBILITY BOUNDARY, as for `proposed_kind`: a proposal file carrying
|
|
4978
|
+
* `action: "rescope"` does not parse on a CLI built before this, and
|
|
4979
|
+
* `loadProposal` throws rather than silently dropping it.
|
|
4980
|
+
*/
|
|
4981
|
+
proposed_scope: z24.string().min(1).max(SCOPE_LIMIT).nullable().default(null),
|
|
4982
|
+
/**
|
|
4983
|
+
* The end date `expire` writes onto the current claim, null elsewhere.
|
|
4984
|
+
*
|
|
4985
|
+
* A date rather than a status: `freshnessOf` reads `valid_until` off the
|
|
4986
|
+
* claim and returns `expired`, which recall already labels and ranks below
|
|
4987
|
+
* `current`. Nothing here decides what expiry MEANS — that was decided
|
|
4988
|
+
* years of code ago and only the writer was missing.
|
|
4989
|
+
*/
|
|
4990
|
+
proposed_valid_until: z24.string().min(1).nullable().default(null),
|
|
4400
4991
|
relations: ProposedRelationsSchema,
|
|
4401
4992
|
/** Why the AI thinks this change is right. Shown at approval time. */
|
|
4402
4993
|
reason: z24.string().min(1),
|
|
@@ -4433,7 +5024,7 @@ var init_schema2 = __esm({
|
|
|
4433
5024
|
path: ["source_excerpt"]
|
|
4434
5025
|
}
|
|
4435
5026
|
).refine((p) => carriesNoClaim(p.action) || p.claim !== null, {
|
|
4436
|
-
message: "only retire, unretire and
|
|
5027
|
+
message: "only retire, unretire, reclassify, unbind, rescope and expire may omit the claim",
|
|
4437
5028
|
path: ["claim"]
|
|
4438
5029
|
}).refine((p) => isClassifyAction(p.action) === (p.proposed_kind !== null), {
|
|
4439
5030
|
message: "proposed_kind belongs to reclassify, and reclassify requires one",
|
|
@@ -4441,6 +5032,18 @@ var init_schema2 = __esm({
|
|
|
4441
5032
|
}).refine((p) => !isClassifyAction(p.action) || p.claim === null, {
|
|
4442
5033
|
message: "reclassify says what sort of memory this is; it does not take a claim",
|
|
4443
5034
|
path: ["claim"]
|
|
5035
|
+
}).refine((p) => isScopeAction(p.action) === (p.proposed_scope !== null), {
|
|
5036
|
+
message: "proposed_scope belongs to rescope, and rescope requires one",
|
|
5037
|
+
path: ["proposed_scope"]
|
|
5038
|
+
}).refine((p) => isValidityAction(p.action) === (p.proposed_valid_until !== null), {
|
|
5039
|
+
message: "proposed_valid_until belongs to expire, and expire requires one",
|
|
5040
|
+
path: ["proposed_valid_until"]
|
|
5041
|
+
}).refine((p) => !isScopeAction(p.action) || p.claim === null, {
|
|
5042
|
+
message: "rescope says where a memory binds; it does not take a claim",
|
|
5043
|
+
path: ["claim"]
|
|
5044
|
+
}).refine((p) => !isValidityAction(p.action) || p.claim === null, {
|
|
5045
|
+
message: "expire says when a memory stops being current; it does not take a claim",
|
|
5046
|
+
path: ["claim"]
|
|
4444
5047
|
});
|
|
4445
5048
|
ACCEPTED = /* @__PURE__ */ Symbol("memgineering.approved");
|
|
4446
5049
|
}
|
|
@@ -4490,12 +5093,42 @@ function detectConsolidation(entries, opts = {}) {
|
|
|
4490
5093
|
...titles
|
|
4491
5094
|
];
|
|
4492
5095
|
const out = rankCandidates(scored);
|
|
5096
|
+
const limit = opts.limit ?? DEFAULT_LIMIT;
|
|
4493
5097
|
return {
|
|
4494
|
-
candidates: out
|
|
5098
|
+
candidates: shareTheList(out, limit),
|
|
5099
|
+
by_rule: countByRule(out),
|
|
4495
5100
|
scanned: budget.scanned,
|
|
4496
5101
|
truncated: budget.truncated
|
|
4497
5102
|
};
|
|
4498
5103
|
}
|
|
5104
|
+
function shareTheList(ranked, limit) {
|
|
5105
|
+
const lanes = /* @__PURE__ */ new Map();
|
|
5106
|
+
for (const candidate of ranked) {
|
|
5107
|
+
const lane = lanes.get(candidate.rule);
|
|
5108
|
+
if (lane) lane.push(candidate);
|
|
5109
|
+
else lanes.set(candidate.rule, [candidate]);
|
|
5110
|
+
}
|
|
5111
|
+
const out = [];
|
|
5112
|
+
const queues = [...lanes.values()];
|
|
5113
|
+
let round = 0;
|
|
5114
|
+
for (; ; ) {
|
|
5115
|
+
let added = false;
|
|
5116
|
+
for (const queue of queues) {
|
|
5117
|
+
if (out.length >= limit) return out;
|
|
5118
|
+
const next = queue[round];
|
|
5119
|
+
if (next === void 0) continue;
|
|
5120
|
+
out.push(next);
|
|
5121
|
+
added = true;
|
|
5122
|
+
}
|
|
5123
|
+
if (!added) return out;
|
|
5124
|
+
round += 1;
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
function countByRule(ranked) {
|
|
5128
|
+
const out = {};
|
|
5129
|
+
for (const candidate of ranked) out[candidate.rule] = (out[candidate.rule] ?? 0) + 1;
|
|
5130
|
+
return out;
|
|
5131
|
+
}
|
|
4499
5132
|
function titleTerms(title) {
|
|
4500
5133
|
const out = /* @__PURE__ */ new Set();
|
|
4501
5134
|
for (const term of terms(title)) {
|
|
@@ -4843,19 +5476,38 @@ function kindPromotions(entries) {
|
|
|
4843
5476
|
const out = [];
|
|
4844
5477
|
for (const entry of entries) {
|
|
4845
5478
|
if (entry.memory.binding !== true) continue;
|
|
4846
|
-
|
|
5479
|
+
const kind = entry.memory.kind;
|
|
5480
|
+
if (kind !== void 0 && RULE_SHAPED_KINDS.has(kind)) continue;
|
|
5481
|
+
if (kind === void 0) {
|
|
5482
|
+
out.push({
|
|
5483
|
+
candidate: {
|
|
5484
|
+
rule: "binding_unclassified",
|
|
5485
|
+
memory_id: entry.memory.id,
|
|
5486
|
+
path: entry.path,
|
|
5487
|
+
title: entry.memory.title,
|
|
5488
|
+
other_id: null,
|
|
5489
|
+
other_path: null,
|
|
5490
|
+
other_title: null,
|
|
5491
|
+
evidence: "marked as binding and left unclassified \u2014 either a decision nobody classified, or something that was never a rule",
|
|
5492
|
+
suggested_action: "decide",
|
|
5493
|
+
suggested_kind: null
|
|
5494
|
+
},
|
|
5495
|
+
confidence: 4
|
|
5496
|
+
});
|
|
5497
|
+
continue;
|
|
5498
|
+
}
|
|
4847
5499
|
out.push({
|
|
4848
5500
|
candidate: {
|
|
4849
|
-
rule: "
|
|
5501
|
+
rule: "rule_demotion",
|
|
4850
5502
|
memory_id: entry.memory.id,
|
|
4851
5503
|
path: entry.path,
|
|
4852
5504
|
title: entry.memory.title,
|
|
4853
5505
|
other_id: null,
|
|
4854
5506
|
other_path: null,
|
|
4855
5507
|
other_title: null,
|
|
4856
|
-
evidence:
|
|
4857
|
-
suggested_action: "
|
|
4858
|
-
suggested_kind:
|
|
5508
|
+
evidence: `marked as binding but classified as ${kind} \u2014 the author said it is not a decision, so it may not be a rule`,
|
|
5509
|
+
suggested_action: "unmark_rule",
|
|
5510
|
+
suggested_kind: null
|
|
4859
5511
|
},
|
|
4860
5512
|
confidence: 4
|
|
4861
5513
|
});
|
|
@@ -4962,7 +5614,7 @@ function* pairsFrom(buckets, budget) {
|
|
|
4962
5614
|
}
|
|
4963
5615
|
}
|
|
4964
5616
|
}
|
|
4965
|
-
var CONSOLIDATION_RULES, DEFAULT_LIMIT, DEFAULT_PAIR_BUDGET, SEMANTIC_PAIR_BUDGET, TITLE_OVERLAP, SAME_SCOPE_SEMANTIC_SIMILARITY, SHARED_ENTITY_SEMANTIC_SIMILARITY, GLOBAL_SEMANTIC_SIMILARITY, RECIPROCAL_NEIGHBOURS, CandidateComponents;
|
|
5617
|
+
var CONSOLIDATION_RULES, DEFAULT_LIMIT, DEFAULT_PAIR_BUDGET, SEMANTIC_PAIR_BUDGET, TITLE_OVERLAP, SAME_SCOPE_SEMANTIC_SIMILARITY, SHARED_ENTITY_SEMANTIC_SIMILARITY, GLOBAL_SEMANTIC_SIMILARITY, RECIPROCAL_NEIGHBOURS, RULE_SHAPED_KINDS, CandidateComponents;
|
|
4966
5618
|
var init_detect = __esm({
|
|
4967
5619
|
"../../packages/memory-engine/src/proposal/detect.ts"() {
|
|
4968
5620
|
"use strict";
|
|
@@ -4973,7 +5625,9 @@ var init_detect = __esm({
|
|
|
4973
5625
|
"semantic_similarity",
|
|
4974
5626
|
"shared_context",
|
|
4975
5627
|
"similar_title",
|
|
4976
|
-
"kind_promotion"
|
|
5628
|
+
"kind_promotion",
|
|
5629
|
+
"rule_demotion",
|
|
5630
|
+
"binding_unclassified"
|
|
4977
5631
|
];
|
|
4978
5632
|
DEFAULT_LIMIT = 50;
|
|
4979
5633
|
DEFAULT_PAIR_BUDGET = 2e5;
|
|
@@ -4983,6 +5637,7 @@ var init_detect = __esm({
|
|
|
4983
5637
|
SHARED_ENTITY_SEMANTIC_SIMILARITY = 0.75;
|
|
4984
5638
|
GLOBAL_SEMANTIC_SIMILARITY = 0.72;
|
|
4985
5639
|
RECIPROCAL_NEIGHBOURS = 2;
|
|
5640
|
+
RULE_SHAPED_KINDS = /* @__PURE__ */ new Set(["decision", "preference"]);
|
|
4986
5641
|
CandidateComponents = class {
|
|
4987
5642
|
parent = /* @__PURE__ */ new Map();
|
|
4988
5643
|
root(id) {
|
|
@@ -5319,12 +5974,12 @@ function commit(prepared, input, opts = {}) {
|
|
|
5319
5974
|
if (carriesNoClaim(parsed.action)) {
|
|
5320
5975
|
if (parsed.claim !== null) {
|
|
5321
5976
|
throw Object.assign(new Error(`${parsed.action} does not take a claim`), {
|
|
5322
|
-
hint: isClassifyAction(parsed.action) ? `${parsed.action} says what sort of memory this is, not what it says. To change the conclusion too, use supersede.` : `${parsed.action} changes whether a memory is current, not what it says. To change the conclusion too, use supersede.`
|
|
5977
|
+
hint: isClassifyAction(parsed.action) ? `${parsed.action} says what sort of memory this is, not what it says. To change the conclusion too, use supersede.` : isBindingAction(parsed.action) ? `${parsed.action} takes a marking back and leaves the conclusion exactly as it is \u2014 that is the whole reason it exists. To change what the note says as well, use supersede.` : isScopeAction(parsed.action) ? `${parsed.action} says where a memory binds, not what it says. To change the conclusion too, use supersede.` : isValidityAction(parsed.action) ? `${parsed.action} gives a memory an end date and leaves the conclusion exactly as it is. To change what the note says as well, use supersede.` : `${parsed.action} changes whether a memory is current, not what it says. To change the conclusion too, use supersede.`
|
|
5323
5978
|
});
|
|
5324
5979
|
}
|
|
5325
5980
|
} else if (parsed.claim === null) {
|
|
5326
5981
|
throw Object.assign(new Error(`${parsed.action} needs a claim`), {
|
|
5327
|
-
hint: "Only retire, unretire and
|
|
5982
|
+
hint: "Only retire, unretire, reclassify, unbind, rescope and expire may omit it. They change a memory's standing, its classification, whether it binds, where it binds or when it stops being current \u2014 rather than its content."
|
|
5328
5983
|
});
|
|
5329
5984
|
} else if ((parsed.action === "supersede" || parsed.action === "create") && parsed.claim.summary === null) {
|
|
5330
5985
|
throw Object.assign(new Error(`${parsed.action} needs a summary as well as a claim`), {
|
|
@@ -5341,6 +5996,26 @@ function commit(prepared, input, opts = {}) {
|
|
|
5341
5996
|
hint: "Only `reclassify` moves a memory's kind, and it does nothing else. Propose it separately, with its own reason."
|
|
5342
5997
|
});
|
|
5343
5998
|
}
|
|
5999
|
+
if (isScopeAction(parsed.action) && parsed.proposed_scope === null) {
|
|
6000
|
+
throw Object.assign(new Error(`${parsed.action} needs the scope it is proposing`), {
|
|
6001
|
+
hint: `Pass a project name, or \`${GLOBAL_SCOPE}\` to say the memory holds everywhere. Widening is spelled out because it cannot be taken back by accident.`
|
|
6002
|
+
});
|
|
6003
|
+
}
|
|
6004
|
+
if (!isScopeAction(parsed.action) && parsed.proposed_scope !== null) {
|
|
6005
|
+
throw Object.assign(new Error(`${parsed.action} does not set the scope`), {
|
|
6006
|
+
hint: "Only `rescope` moves where a memory binds, and it does nothing else. Propose it separately, with its own reason."
|
|
6007
|
+
});
|
|
6008
|
+
}
|
|
6009
|
+
if (isValidityAction(parsed.action) && parsed.proposed_valid_until === null) {
|
|
6010
|
+
throw Object.assign(new Error(`${parsed.action} needs the date it is proposing`), {
|
|
6011
|
+
hint: "Pass an ISO date \u2014 the day the memory stops being current. It is not retired by this: recall still returns it, ranked below what is current and labelled."
|
|
6012
|
+
});
|
|
6013
|
+
}
|
|
6014
|
+
if (!isValidityAction(parsed.action) && parsed.proposed_valid_until !== null) {
|
|
6015
|
+
throw Object.assign(new Error(`${parsed.action} does not set an end date`), {
|
|
6016
|
+
hint: "Only `expire` gives a memory an end date, and it does nothing else. Propose it separately, with its own reason."
|
|
6017
|
+
});
|
|
6018
|
+
}
|
|
5344
6019
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
5345
6020
|
const at = now.toISOString();
|
|
5346
6021
|
const draft = {
|
|
@@ -5350,6 +6025,8 @@ function commit(prepared, input, opts = {}) {
|
|
|
5350
6025
|
memory_id: parsed.memory_id,
|
|
5351
6026
|
claim: parsed.claim,
|
|
5352
6027
|
proposed_kind: parsed.proposed_kind,
|
|
6028
|
+
proposed_scope: parsed.proposed_scope,
|
|
6029
|
+
proposed_valid_until: parsed.proposed_valid_until,
|
|
5353
6030
|
relations: parsed.relations,
|
|
5354
6031
|
reason: parsed.reason,
|
|
5355
6032
|
source_excerpt: parsed.source_excerpt,
|
|
@@ -5380,14 +6057,22 @@ var init_commit = __esm({
|
|
|
5380
6057
|
*/
|
|
5381
6058
|
memory_id: z26.string().min(1).nullable().default(null),
|
|
5382
6059
|
/**
|
|
5383
|
-
* Omitted by `retire` / `unretire` / `reclassify`, which change a
|
|
5384
|
-
* standing
|
|
5385
|
-
* the other action rules so the error can
|
|
5386
|
-
* at a field.
|
|
6060
|
+
* Omitted by `retire` / `unretire` / `reclassify` / `unbind`, which change a
|
|
6061
|
+
* memory's standing, its classification or whether it binds — rather than
|
|
6062
|
+
* what it says. Checked below with the other action rules so the error can
|
|
6063
|
+
* name the action instead of pointing at a field.
|
|
5387
6064
|
*/
|
|
5388
6065
|
claim: ProposedClaimSchema.nullable().default(null),
|
|
5389
6066
|
/** What `reclassify` is reclassifying this memory AS. Only that action takes one. */
|
|
5390
6067
|
proposed_kind: MemoryKindSchema.nullable().default(null),
|
|
6068
|
+
/**
|
|
6069
|
+
* Where `rescope` moves this memory to — a scope name, or the reserved word
|
|
6070
|
+
* `global`. Only that action takes one, and it may not be null: see
|
|
6071
|
+
* `ProposalSchema.proposed_scope` for why "absent" must not spell "widen".
|
|
6072
|
+
*/
|
|
6073
|
+
proposed_scope: z26.string().min(1).max(SCOPE_LIMIT).nullable().default(null),
|
|
6074
|
+
/** The end date `expire` writes onto the current claim. Only that action takes one. */
|
|
6075
|
+
proposed_valid_until: z26.string().min(1).nullable().default(null),
|
|
5391
6076
|
relations: ProposedRelationsSchema.default({}),
|
|
5392
6077
|
reason: z26.string().min(1),
|
|
5393
6078
|
/** The passage from the note that justifies this. Required to submit. */
|
|
@@ -5488,6 +6173,68 @@ function reclassifyInput(entry, kind, opts = {}) {
|
|
|
5488
6173
|
target_path: entry.path
|
|
5489
6174
|
};
|
|
5490
6175
|
}
|
|
6176
|
+
function unbindInput(entry, opts = {}) {
|
|
6177
|
+
return {
|
|
6178
|
+
action: "unbind",
|
|
6179
|
+
memory_id: entry.memory.id,
|
|
6180
|
+
claim: null,
|
|
6181
|
+
reason: opts.reason ?? "no longer binding",
|
|
6182
|
+
source_excerpt: opts.because ?? entry.memory.summary ?? entry.memory.title,
|
|
6183
|
+
target_path: entry.path
|
|
6184
|
+
};
|
|
6185
|
+
}
|
|
6186
|
+
function rescopeInput(entry, scope, opts = {}) {
|
|
6187
|
+
const wanted = scope.trim();
|
|
6188
|
+
if (wanted === "") {
|
|
6189
|
+
throw Object.assign(new Error("a scope cannot be empty"), {
|
|
6190
|
+
hint: `Name the project this memory binds in, or \`${GLOBAL_SCOPE}\` to say it holds everywhere.`
|
|
6191
|
+
});
|
|
6192
|
+
}
|
|
6193
|
+
if ([...wanted].length > SCOPE_LIMIT) {
|
|
6194
|
+
throw Object.assign(new Error(`a scope may be at most ${SCOPE_LIMIT} characters`), {
|
|
6195
|
+
hint: "A scope names a project. If it needs a sentence, it belongs in the note."
|
|
6196
|
+
});
|
|
6197
|
+
}
|
|
6198
|
+
const declared = declaredScopeOf(entry.memory);
|
|
6199
|
+
const same = isGlobalScope(wanted) ? declared === null : declared === wanted;
|
|
6200
|
+
if (same) {
|
|
6201
|
+
throw Object.assign(new Error(`${entry.memory.title} already binds there`), {
|
|
6202
|
+
hint: "Nothing was written, and nothing needed to be."
|
|
6203
|
+
});
|
|
6204
|
+
}
|
|
6205
|
+
return {
|
|
6206
|
+
action: "rescope",
|
|
6207
|
+
memory_id: entry.memory.id,
|
|
6208
|
+
claim: null,
|
|
6209
|
+
proposed_scope: wanted,
|
|
6210
|
+
reason: opts.reason ?? `binds in ${wanted}`,
|
|
6211
|
+
source_excerpt: opts.because ?? entry.memory.summary ?? entry.memory.title,
|
|
6212
|
+
target_path: entry.path
|
|
6213
|
+
};
|
|
6214
|
+
}
|
|
6215
|
+
function expireInput(entry, until, opts = {}) {
|
|
6216
|
+
const wanted = until.trim();
|
|
6217
|
+
const at = Date.parse(wanted);
|
|
6218
|
+
if (!Number.isFinite(at)) {
|
|
6219
|
+
throw Object.assign(new Error(`${until} is not a date`), {
|
|
6220
|
+
hint: "Pass an ISO date, such as 2026-10-31 or 2026-10-31T00:00:00Z."
|
|
6221
|
+
});
|
|
6222
|
+
}
|
|
6223
|
+
if ((entry.claims[0]?.valid_until ?? entry.memory.valid_until ?? null) === wanted) {
|
|
6224
|
+
throw Object.assign(new Error(`${entry.memory.title} already ends then`), {
|
|
6225
|
+
hint: "Nothing was written, and nothing needed to be."
|
|
6226
|
+
});
|
|
6227
|
+
}
|
|
6228
|
+
return {
|
|
6229
|
+
action: "expire",
|
|
6230
|
+
memory_id: entry.memory.id,
|
|
6231
|
+
claim: null,
|
|
6232
|
+
proposed_valid_until: wanted,
|
|
6233
|
+
reason: opts.reason ?? `holds until ${wanted}`,
|
|
6234
|
+
source_excerpt: opts.because ?? entry.memory.summary ?? entry.memory.title,
|
|
6235
|
+
target_path: entry.path
|
|
6236
|
+
};
|
|
6237
|
+
}
|
|
5491
6238
|
function saysNothingNew(entry, input, normalize) {
|
|
5492
6239
|
const norm = (v) => normalize(v ?? "").trim();
|
|
5493
6240
|
const claim = input.claim;
|
|
@@ -5495,6 +6242,7 @@ function saysNothingNew(entry, input, normalize) {
|
|
|
5495
6242
|
if (norm(claim.text) !== norm(previousClaim(entry))) return false;
|
|
5496
6243
|
if (claim.summary != null && norm(claim.summary) !== norm(entry.memory.summary)) return false;
|
|
5497
6244
|
if (claim.title != null && norm(claim.title) !== norm(entry.memory.title)) return false;
|
|
6245
|
+
if (claim.binding != null && claim.binding !== (entry.memory.binding === true)) return false;
|
|
5498
6246
|
const declared = new Set(
|
|
5499
6247
|
entry.relations.filter((r) => r.type === "contradicts").map((r) => r.to)
|
|
5500
6248
|
);
|
|
@@ -5507,11 +6255,6 @@ function bodyStillAsserts(content, oldClaim, newClaim, normalize) {
|
|
|
5507
6255
|
if (line === normalize(newClaim?.split("\n")[0] ?? "").trim()) return null;
|
|
5508
6256
|
return bodyOf(content).includes(line) ? line : null;
|
|
5509
6257
|
}
|
|
5510
|
-
function bodyOf(content) {
|
|
5511
|
-
const stripped = content.replace(/^/, "");
|
|
5512
|
-
const fence2 = /^---[ \t]*\r?\n[\s\S]*?\r?\n---[ \t]*(\r?\n|$)/.exec(stripped);
|
|
5513
|
-
return fence2 ? stripped.slice(fence2[0].length) : stripped;
|
|
5514
|
-
}
|
|
5515
6258
|
function previousClaim(entry) {
|
|
5516
6259
|
const current = entry.claims.find((claim) => claim.id === entry.memory.current_claim) ?? entry.claims[0];
|
|
5517
6260
|
return current?.text ?? null;
|
|
@@ -5527,6 +6270,9 @@ var init_curate = __esm({
|
|
|
5527
6270
|
"../../packages/memory-engine/src/capture/curate.ts"() {
|
|
5528
6271
|
"use strict";
|
|
5529
6272
|
init_planner();
|
|
6273
|
+
init_schema();
|
|
6274
|
+
init_rule_budget();
|
|
6275
|
+
init_note_body();
|
|
5530
6276
|
NO_REASON_GIVEN = "revised directly";
|
|
5531
6277
|
noLifecycleReason = (action) => `${action}d directly`;
|
|
5532
6278
|
}
|
|
@@ -5577,6 +6323,25 @@ function desiredFields(proposal, existing) {
|
|
|
5577
6323
|
out["kind"] = proposal.proposed_kind;
|
|
5578
6324
|
return out;
|
|
5579
6325
|
}
|
|
6326
|
+
if (isBindingAction(proposal.action)) {
|
|
6327
|
+
delete out["binding"];
|
|
6328
|
+
return out;
|
|
6329
|
+
}
|
|
6330
|
+
if (isScopeAction(proposal.action)) {
|
|
6331
|
+
if (proposal.proposed_scope === null) {
|
|
6332
|
+
throw new Error(`${proposal.action} reached the patcher with no scope`);
|
|
6333
|
+
}
|
|
6334
|
+
if (isGlobalScope(proposal.proposed_scope)) delete out["scope"];
|
|
6335
|
+
else out["scope"] = proposal.proposed_scope;
|
|
6336
|
+
return out;
|
|
6337
|
+
}
|
|
6338
|
+
if (isValidityAction(proposal.action)) {
|
|
6339
|
+
if (proposal.proposed_valid_until === null) {
|
|
6340
|
+
throw new Error(`${proposal.action} reached the patcher with no date`);
|
|
6341
|
+
}
|
|
6342
|
+
out["valid_until"] = proposal.proposed_valid_until;
|
|
6343
|
+
return out;
|
|
6344
|
+
}
|
|
5580
6345
|
const claim = proposal.claim;
|
|
5581
6346
|
if (claim === null) {
|
|
5582
6347
|
throw new Error(`${proposal.action} reached the patcher with no claim`);
|
|
@@ -5874,6 +6639,108 @@ function verifyPatch(patched, proposal, before) {
|
|
|
5874
6639
|
}
|
|
5875
6640
|
return;
|
|
5876
6641
|
}
|
|
6642
|
+
if (isBindingAction(proposal.action)) {
|
|
6643
|
+
if (mapped.memory.binding === true) {
|
|
6644
|
+
throw new PatchError(
|
|
6645
|
+
"the patched note still reads as binding",
|
|
6646
|
+
"This is a defect in the patcher, not in your note. Nothing was written."
|
|
6647
|
+
);
|
|
6648
|
+
}
|
|
6649
|
+
if (before === void 0) {
|
|
6650
|
+
throw new PatchError(
|
|
6651
|
+
`${proposal.action} cannot be verified without the note it started from`,
|
|
6652
|
+
"This is a defect in the caller, not in your note. Nothing was written."
|
|
6653
|
+
);
|
|
6654
|
+
}
|
|
6655
|
+
const was = mapNoteToMemory({ path: proposal.target.path, content: before, revision: null });
|
|
6656
|
+
if (was.claims[0]?.text !== mapped.claims[0]?.text) {
|
|
6657
|
+
throw new PatchError(
|
|
6658
|
+
`${proposal.action} changed the conclusion, which it must never do`,
|
|
6659
|
+
"Taking a marking back leaves what the note says exactly as it was. Nothing was written."
|
|
6660
|
+
);
|
|
6661
|
+
}
|
|
6662
|
+
if (was.memory.summary !== mapped.memory.summary) {
|
|
6663
|
+
throw new PatchError(
|
|
6664
|
+
`${proposal.action} changed the summary, which it must never do`,
|
|
6665
|
+
"Taking a marking back leaves what the note says exactly as it was \u2014 and the summary is what recall matches on. Nothing was written."
|
|
6666
|
+
);
|
|
6667
|
+
}
|
|
6668
|
+
if (was.memory.title !== mapped.memory.title) {
|
|
6669
|
+
throw new PatchError(
|
|
6670
|
+
`${proposal.action} changed the title, which it must never do`,
|
|
6671
|
+
"Taking a marking back leaves what the note says exactly as it was. Nothing was written."
|
|
6672
|
+
);
|
|
6673
|
+
}
|
|
6674
|
+
if (was.memory.status !== mapped.memory.status) {
|
|
6675
|
+
throw new PatchError(
|
|
6676
|
+
`${proposal.action} changed the status, which it must never do`,
|
|
6677
|
+
"A memory that no longer binds is still current. To take it out of the answers as well, use retire. Nothing was written."
|
|
6678
|
+
);
|
|
6679
|
+
}
|
|
6680
|
+
return;
|
|
6681
|
+
}
|
|
6682
|
+
if (isScopeAction(proposal.action) || isValidityAction(proposal.action)) {
|
|
6683
|
+
if (before === void 0) {
|
|
6684
|
+
throw new PatchError(
|
|
6685
|
+
`${proposal.action} cannot be verified without the note it started from`,
|
|
6686
|
+
"This is a defect in the caller, not in your note. Nothing was written."
|
|
6687
|
+
);
|
|
6688
|
+
}
|
|
6689
|
+
if (isScopeAction(proposal.action)) {
|
|
6690
|
+
const want = proposal.proposed_scope;
|
|
6691
|
+
const got = declaredScopeOf(mapped.memory);
|
|
6692
|
+
const landed = isGlobalScope(want) ? got === null : got === want;
|
|
6693
|
+
if (!landed) {
|
|
6694
|
+
throw new PatchError(
|
|
6695
|
+
"the patched note does not declare the scope that was asked for",
|
|
6696
|
+
"This is a defect in the patcher, not in your note. Nothing was written."
|
|
6697
|
+
);
|
|
6698
|
+
}
|
|
6699
|
+
} else if (
|
|
6700
|
+
// Read back the way `freshnessOf` reads it: the claim's date when the
|
|
6701
|
+
// note states a claim, the note's own otherwise. Asserting only on the
|
|
6702
|
+
// claim would reject every note `remember` wrote, since it has never
|
|
6703
|
+
// written a `claim:` key.
|
|
6704
|
+
(mapped.claims[0]?.valid_until ?? mapped.memory.valid_until ?? null) !== proposal.proposed_valid_until
|
|
6705
|
+
) {
|
|
6706
|
+
throw new PatchError(
|
|
6707
|
+
"the patched note does not carry the end date that was asked for",
|
|
6708
|
+
"This is a defect in the patcher, not in your note. Nothing was written."
|
|
6709
|
+
);
|
|
6710
|
+
}
|
|
6711
|
+
const was = mapNoteToMemory({ path: proposal.target.path, content: before, revision: null });
|
|
6712
|
+
if (was.claims[0]?.text !== mapped.claims[0]?.text) {
|
|
6713
|
+
throw new PatchError(
|
|
6714
|
+
`${proposal.action} changed the conclusion, which it must never do`,
|
|
6715
|
+
"It changes one field and leaves what the note says exactly as it was. Nothing was written."
|
|
6716
|
+
);
|
|
6717
|
+
}
|
|
6718
|
+
if (was.memory.summary !== mapped.memory.summary) {
|
|
6719
|
+
throw new PatchError(
|
|
6720
|
+
`${proposal.action} changed the summary, which it must never do`,
|
|
6721
|
+
"The summary is what recall matches on, and this action does not touch what the note says. Nothing was written."
|
|
6722
|
+
);
|
|
6723
|
+
}
|
|
6724
|
+
if (was.memory.title !== mapped.memory.title) {
|
|
6725
|
+
throw new PatchError(
|
|
6726
|
+
`${proposal.action} changed the title, which it must never do`,
|
|
6727
|
+
"It changes one field and leaves what the note says exactly as it was. Nothing was written."
|
|
6728
|
+
);
|
|
6729
|
+
}
|
|
6730
|
+
if (was.memory.status !== mapped.memory.status) {
|
|
6731
|
+
throw new PatchError(
|
|
6732
|
+
`${proposal.action} changed the status, which it must never do`,
|
|
6733
|
+
"Moving where a memory binds, or saying when it stops being current, does not retire it. To take it out of the answers, use retire. Nothing was written."
|
|
6734
|
+
);
|
|
6735
|
+
}
|
|
6736
|
+
if (was.memory.binding !== mapped.memory.binding) {
|
|
6737
|
+
throw new PatchError(
|
|
6738
|
+
`${proposal.action} changed whether the memory binds, which it must never do`,
|
|
6739
|
+
"To take a marking back, use `revise --no-rule`. Nothing was written."
|
|
6740
|
+
);
|
|
6741
|
+
}
|
|
6742
|
+
return;
|
|
6743
|
+
}
|
|
5877
6744
|
const supersedes = new Set(
|
|
5878
6745
|
mapped.relations.filter((r) => r.type === "supersedes").map((r) => r.to)
|
|
5879
6746
|
);
|
|
@@ -5944,11 +6811,13 @@ function reversePatch(content, patch) {
|
|
|
5944
6811
|
}
|
|
5945
6812
|
return null;
|
|
5946
6813
|
}
|
|
5947
|
-
var PATCHABLE_KEYS, NEVER_WRITTEN_KEYS, STATUS_WRITING_ACTIONS, KIND_WRITING_ACTIONS, NAMESPACE2, FENCE_RE, LOOKS_FENCED_RE, PatchError, BLOCK_KEY_RE, ANY_INDENTED_KEY_RE;
|
|
6814
|
+
var PATCHABLE_KEYS, NEVER_WRITTEN_KEYS, STATUS_WRITING_ACTIONS, KIND_WRITING_ACTIONS, SCOPE_WRITING_ACTIONS, NAMESPACE2, FENCE_RE, LOOKS_FENCED_RE, PatchError, BLOCK_KEY_RE, ANY_INDENTED_KEY_RE;
|
|
5948
6815
|
var init_patch = __esm({
|
|
5949
6816
|
"../../packages/memory-engine/src/proposal/patch.ts"() {
|
|
5950
6817
|
"use strict";
|
|
5951
6818
|
init_markdown_mapping();
|
|
6819
|
+
init_rule_budget();
|
|
6820
|
+
init_schema();
|
|
5952
6821
|
init_schema2();
|
|
5953
6822
|
PATCHABLE_KEYS = [
|
|
5954
6823
|
// The conclusion itself.
|
|
@@ -5972,6 +6841,7 @@ var init_patch = __esm({
|
|
|
5972
6841
|
NEVER_WRITTEN_KEYS = ["id", "type", "scope", "aliases", "status", "kind"];
|
|
5973
6842
|
STATUS_WRITING_ACTIONS = ["retire", "unretire"];
|
|
5974
6843
|
KIND_WRITING_ACTIONS = ["reclassify"];
|
|
6844
|
+
SCOPE_WRITING_ACTIONS = ["rescope"];
|
|
5975
6845
|
NAMESPACE2 = "memgineering";
|
|
5976
6846
|
FENCE_RE = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(\r?\n|$)/;
|
|
5977
6847
|
LOOKS_FENCED_RE = /^---[ \t]*\r?\n/;
|
|
@@ -6013,15 +6883,15 @@ async function applyProposal(adapter, accepted) {
|
|
|
6013
6883
|
const patch = computePatch(current.content, proposal);
|
|
6014
6884
|
verifyPatch(patch.content, proposal, current.content);
|
|
6015
6885
|
if (patch.content === current.content) {
|
|
6016
|
-
const
|
|
6017
|
-
if (
|
|
6886
|
+
const base2 = proposal.target.baseRevision;
|
|
6887
|
+
if (base2 === null || base2 === void 0) {
|
|
6018
6888
|
return {
|
|
6019
6889
|
ok: false,
|
|
6020
6890
|
reason: "revision_conflict",
|
|
6021
6891
|
proposal: needsRebase(proposal, current.revision)
|
|
6022
6892
|
};
|
|
6023
6893
|
}
|
|
6024
|
-
if (adapter.compareRevision(
|
|
6894
|
+
if (adapter.compareRevision(base2, current.revision) === "diverged") {
|
|
6025
6895
|
return {
|
|
6026
6896
|
ok: false,
|
|
6027
6897
|
reason: "revision_conflict",
|
|
@@ -6088,23 +6958,36 @@ function rank(entries, events, opts) {
|
|
|
6088
6958
|
const recalls = events.filter((e) => !AUTOMATIC.has(e.verb));
|
|
6089
6959
|
const here = opts.here ? recalls.filter((e) => opts.here(e)) : [];
|
|
6090
6960
|
const hereLabel = opts.hereLabel ?? "in this folder";
|
|
6091
|
-
const
|
|
6092
|
-
const
|
|
6961
|
+
const usageIn = (source) => {
|
|
6962
|
+
const usage = /* @__PURE__ */ new Map();
|
|
6963
|
+
const at = (id) => {
|
|
6964
|
+
let u = usage.get(id);
|
|
6965
|
+
if (!u) usage.set(id, u = { opened: 0, surfaced: 0, credit: 0 });
|
|
6966
|
+
return u;
|
|
6967
|
+
};
|
|
6093
6968
|
for (const event of source) {
|
|
6094
|
-
|
|
6095
|
-
|
|
6969
|
+
if (event.verb === "recall") {
|
|
6970
|
+
event.returned_ids.forEach((id, i) => {
|
|
6971
|
+
const u = at(id);
|
|
6972
|
+
u.surfaced += 1;
|
|
6973
|
+
if (i === 0) u.credit += SURFACED_SHARE;
|
|
6974
|
+
});
|
|
6975
|
+
} else if (DELIBERATE.has(event.verb)) {
|
|
6976
|
+
const ids = event.opened_id ? [event.opened_id] : event.returned_ids;
|
|
6977
|
+
for (const id of new Set(ids)) at(id).opened += 1;
|
|
6978
|
+
}
|
|
6096
6979
|
}
|
|
6097
|
-
return
|
|
6980
|
+
return usage;
|
|
6098
6981
|
};
|
|
6099
|
-
const
|
|
6100
|
-
const
|
|
6982
|
+
const evidence = (u) => u ? u.opened + u.credit : 0;
|
|
6983
|
+
const hereUsage = usageIn(here);
|
|
6984
|
+
const anyUsage = usageIn(recalls);
|
|
6101
6985
|
const lastTouched = /* @__PURE__ */ new Map();
|
|
6102
6986
|
for (const event of recalls) {
|
|
6103
6987
|
const t = Date.parse(event.ts);
|
|
6104
6988
|
if (!Number.isFinite(t)) continue;
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
}
|
|
6989
|
+
const touched = event.verb === "recall" ? event.returned_ids.slice(0, 1) : DELIBERATE.has(event.verb) ? [event.opened_id ?? "", ...event.returned_ids].filter(Boolean) : [];
|
|
6990
|
+
for (const id of touched) lastTouched.set(id, Math.max(lastTouched.get(id) ?? 0, t));
|
|
6108
6991
|
}
|
|
6109
6992
|
const hasBase = entries.some((e) => e.path.startsWith("01_BASE/"));
|
|
6110
6993
|
const scored = [];
|
|
@@ -6114,16 +6997,30 @@ function rank(entries, events, opts) {
|
|
|
6114
6997
|
if (freshness === "retired") continue;
|
|
6115
6998
|
const why = [];
|
|
6116
6999
|
let score = 0;
|
|
6117
|
-
const
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
7000
|
+
const hereU = hereUsage.get(id);
|
|
7001
|
+
const anyU = anyUsage.get(id);
|
|
7002
|
+
const hereEvidence = evidence(hereU);
|
|
7003
|
+
const elsewhereEvidence = evidence(anyU) - hereEvidence;
|
|
7004
|
+
if (hereEvidence > 0) {
|
|
7005
|
+
score += WEIGHT.contextRecall * Math.log2(1 + hereEvidence);
|
|
7006
|
+
why.push(usageLine(hereU, hereLabel));
|
|
7007
|
+
}
|
|
7008
|
+
if (elsewhereEvidence > 1e-9) {
|
|
7009
|
+
score += WEIGHT.anyRecall * Math.log2(1 + elsewhereEvidence);
|
|
7010
|
+
if (hereEvidence === 0) {
|
|
7011
|
+
why.push(
|
|
7012
|
+
usageLine(
|
|
7013
|
+
{
|
|
7014
|
+
opened: anyU.opened - (hereU?.opened ?? 0),
|
|
7015
|
+
surfaced: anyU.surfaced - (hereU?.surfaced ?? 0)
|
|
7016
|
+
},
|
|
7017
|
+
"elsewhere"
|
|
7018
|
+
)
|
|
7019
|
+
);
|
|
7020
|
+
}
|
|
6126
7021
|
}
|
|
7022
|
+
const hereCount = (hereU?.opened ?? 0) + (hereU?.surfaced ?? 0);
|
|
7023
|
+
const anyCount = (anyU?.opened ?? 0) + (anyU?.surfaced ?? 0) - hereCount;
|
|
6127
7024
|
const touched = lastTouched.get(id);
|
|
6128
7025
|
if (touched !== void 0) {
|
|
6129
7026
|
const days = (opts.now.getTime() - touched) / 864e5;
|
|
@@ -6144,16 +7041,28 @@ function rank(entries, events, opts) {
|
|
|
6144
7041
|
}
|
|
6145
7042
|
if (score === 0 && !entry.path.startsWith("01_BASE/")) {
|
|
6146
7043
|
score += WEIGHT.neverReached;
|
|
6147
|
-
why.push(
|
|
7044
|
+
why.push(
|
|
7045
|
+
anyU && anyU.surfaced > 0 ? usageLine(
|
|
7046
|
+
{ opened: 0, surfaced: anyU.surfaced },
|
|
7047
|
+
// Labelled by where it happened: all here, none here, or both —
|
|
7048
|
+
// a total said "in this project" would claim the whole count.
|
|
7049
|
+
!hereU?.surfaced ? "elsewhere" : hereU.surfaced === anyU.surfaced ? hereLabel : `(${hereU.surfaced}\xD7 ${hereLabel})`
|
|
7050
|
+
) : "never surfaced yet"
|
|
7051
|
+
);
|
|
6148
7052
|
}
|
|
6149
7053
|
if (freshness !== "current") why.push(freshness);
|
|
6150
|
-
if (score > 0) scored.push({ entry, score, why });
|
|
7054
|
+
if (score > 0) scored.push({ entry, score, why, used: hereCount > 0 || anyCount > 0 });
|
|
6151
7055
|
}
|
|
6152
7056
|
return scored.sort(
|
|
6153
7057
|
(a, b) => b.score - a.score || a.entry.memory.id.localeCompare(b.entry.memory.id)
|
|
6154
7058
|
);
|
|
6155
7059
|
}
|
|
6156
|
-
|
|
7060
|
+
function usageLine(u, where) {
|
|
7061
|
+
if (u.opened === 0) return `surfaced ${u.surfaced}\xD7 ${where}, never opened`;
|
|
7062
|
+
if (u.surfaced === 0) return `opened ${u.opened}\xD7 ${where}`;
|
|
7063
|
+
return `opened ${u.opened}\xD7 \xB7 surfaced ${u.surfaced}\xD7 ${where}`;
|
|
7064
|
+
}
|
|
7065
|
+
var WEIGHT, STALE_BASE_DAYS, SURFACED_SHARE, DELIBERATE;
|
|
6157
7066
|
var init_rank = __esm({
|
|
6158
7067
|
"../../packages/memory-engine/src/resurface/rank.ts"() {
|
|
6159
7068
|
"use strict";
|
|
@@ -6206,26 +7115,35 @@ var init_rank = __esm({
|
|
|
6206
7115
|
binding: 5
|
|
6207
7116
|
};
|
|
6208
7117
|
STALE_BASE_DAYS = 30;
|
|
7118
|
+
SURFACED_SHARE = 0.5;
|
|
7119
|
+
DELIBERATE = /* @__PURE__ */ new Set(["open", "publish", "adapt", "read-public"]);
|
|
6209
7120
|
}
|
|
6210
7121
|
});
|
|
6211
7122
|
|
|
6212
7123
|
// ../../packages/memory-engine/src/index.ts
|
|
6213
7124
|
var src_exports2 = {};
|
|
6214
7125
|
__export(src_exports2, {
|
|
7126
|
+
BASE_TEMPLATES: () => BASE_TEMPLATES,
|
|
6215
7127
|
CONSOLIDATION_RULES: () => CONSOLIDATION_RULES,
|
|
6216
7128
|
CaptureCandidateSchema: () => CaptureCandidateSchema,
|
|
6217
7129
|
ClaimConfidenceSchema: () => ClaimConfidenceSchema,
|
|
6218
7130
|
ClaimSchema: () => ClaimSchema,
|
|
6219
7131
|
CommitInputSchema: () => CommitInputSchema,
|
|
7132
|
+
DEFAULT_RULE_BUDGET: () => DEFAULT_RULE_BUDGET,
|
|
6220
7133
|
DEFAULT_TTL_DAYS: () => DEFAULT_TTL_DAYS,
|
|
7134
|
+
DERIVED_BLUEPRINT: () => DERIVED_BLUEPRINT,
|
|
7135
|
+
DERIVED_DIR: () => DERIVED_DIR,
|
|
7136
|
+
GLOBAL_SCOPE: () => GLOBAL_SCOPE,
|
|
6221
7137
|
IllegalTransitionError: () => IllegalTransitionError,
|
|
6222
7138
|
KIND_WRITING_ACTIONS: () => KIND_WRITING_ACTIONS,
|
|
7139
|
+
MEANING_ONLY_NOTE: () => MEANING_ONLY_NOTE,
|
|
6223
7140
|
MappingModeSchema: () => MappingModeSchema,
|
|
6224
7141
|
MemoryKindSchema: () => MemoryKindSchema,
|
|
6225
7142
|
MemorySchema: () => MemorySchema,
|
|
6226
7143
|
MemoryStatusSchema: () => MemoryStatusSchema,
|
|
6227
7144
|
NEVER_WRITTEN_KEYS: () => NEVER_WRITTEN_KEYS,
|
|
6228
7145
|
NO_REASON_GIVEN: () => NO_REASON_GIVEN,
|
|
7146
|
+
OBSERVATIONS_DIR: () => OBSERVATIONS_DIR,
|
|
6229
7147
|
PATCHABLE_KEYS: () => PATCHABLE_KEYS,
|
|
6230
7148
|
PatchError: () => PatchError,
|
|
6231
7149
|
ProposalActionSchema: () => ProposalActionSchema,
|
|
@@ -6234,14 +7152,23 @@ __export(src_exports2, {
|
|
|
6234
7152
|
ProposedClaimSchema: () => ProposedClaimSchema,
|
|
6235
7153
|
ProposedRelationsSchema: () => ProposedRelationsSchema,
|
|
6236
7154
|
ProvenanceSchema: () => ProvenanceSchema,
|
|
7155
|
+
QUERY_EMBEDDING_PREFIX: () => QUERY_EMBEDDING_PREFIX,
|
|
6237
7156
|
RECALL_DEPTHS: () => RECALL_DEPTHS,
|
|
7157
|
+
RETIRED_BASE_TEMPLATES: () => RETIRED_BASE_TEMPLATES,
|
|
7158
|
+
RULE_BLOCK_BUDGET: () => RULE_BLOCK_BUDGET,
|
|
7159
|
+
RULE_WIDTH_MAX: () => RULE_WIDTH_MAX,
|
|
7160
|
+
RULE_WIDTH_MIN: () => RULE_WIDTH_MIN,
|
|
7161
|
+
RULE_WIRE_WIDTH: () => RULE_WIRE_WIDTH,
|
|
6238
7162
|
RecallOptionError: () => RecallOptionError,
|
|
6239
7163
|
RelationSchema: () => RelationSchema,
|
|
6240
7164
|
RelationSourceSchema: () => RelationSourceSchema,
|
|
6241
7165
|
RelationTypeSchema: () => RelationTypeSchema,
|
|
6242
7166
|
SCOPE_LIMIT: () => SCOPE_LIMIT,
|
|
7167
|
+
SCOPE_SPREAD_FIELD: () => SCOPE_SPREAD_FIELD,
|
|
7168
|
+
SCOPE_WRITING_ACTIONS: () => SCOPE_WRITING_ACTIONS,
|
|
6243
7169
|
SEMANTIC_CANDIDATES: () => SEMANTIC_CANDIDATES,
|
|
6244
7170
|
SEMANTIC_FIELDS: () => SEMANTIC_FIELDS,
|
|
7171
|
+
SETUP_PROGRESS_CODES: () => SETUP_PROGRESS_CODES,
|
|
6245
7172
|
STATUS_FOR_ACTION: () => STATUS_FOR_ACTION,
|
|
6246
7173
|
STATUS_WRITING_ACTIONS: () => STATUS_WRITING_ACTIONS,
|
|
6247
7174
|
StorableActionSchema: () => StorableActionSchema,
|
|
@@ -6249,6 +7176,7 @@ __export(src_exports2, {
|
|
|
6249
7176
|
TELEMETRY_MESSAGE_LIMIT: () => TELEMETRY_MESSAGE_LIMIT,
|
|
6250
7177
|
TelemetryErrorPayloadSchema: () => TelemetryErrorPayloadSchema2,
|
|
6251
7178
|
TransitionSchema: () => TransitionSchema,
|
|
7179
|
+
UNFILLED_FIELDS: () => UNFILLED_FIELDS,
|
|
6252
7180
|
accept: () => accept,
|
|
6253
7181
|
addedLines: () => addedLines,
|
|
6254
7182
|
applyProposal: () => applyProposal,
|
|
@@ -6270,28 +7198,39 @@ __export(src_exports2, {
|
|
|
6270
7198
|
commit: () => commit,
|
|
6271
7199
|
computePatch: () => computePatch,
|
|
6272
7200
|
confidenceOf: () => confidenceOf,
|
|
7201
|
+
declaredScope: () => declaredScope,
|
|
7202
|
+
declaredScopeOf: () => declaredScopeOf,
|
|
6273
7203
|
defaultExpiry: () => defaultExpiry,
|
|
6274
7204
|
defaultStateRoot: () => defaultStateRoot,
|
|
6275
7205
|
deleteProposal: () => deleteProposal,
|
|
6276
7206
|
detectConsolidation: () => detectConsolidation,
|
|
6277
7207
|
expireIfDue: () => expireIfDue,
|
|
7208
|
+
expireInput: () => expireInput,
|
|
6278
7209
|
findConflicts: () => findConflicts,
|
|
6279
7210
|
freshnessOf: () => freshnessOf,
|
|
7211
|
+
isBindingAction: () => isBindingAction,
|
|
6280
7212
|
isClassifyAction: () => isClassifyAction,
|
|
7213
|
+
isExactUntouchedBase: () => isExactUntouchedBase,
|
|
6281
7214
|
isExpired: () => isExpired2,
|
|
7215
|
+
isGlobalScope: () => isGlobalScope,
|
|
6282
7216
|
isLifecycleAction: () => isLifecycleAction,
|
|
6283
7217
|
isRecallDepth: () => isRecallDepth,
|
|
7218
|
+
isScopeAction: () => isScopeAction,
|
|
7219
|
+
isTemplateBody: () => isTemplateBody,
|
|
6284
7220
|
isTerminal: () => isTerminal,
|
|
6285
|
-
|
|
7221
|
+
isUnwrittenBody: () => isUnwrittenBody,
|
|
7222
|
+
isValidityAction: () => isValidityAction,
|
|
6286
7223
|
lifecycleInput: () => lifecycleInput,
|
|
6287
7224
|
listProposals: () => listProposals,
|
|
6288
7225
|
loadProposal: () => loadProposal,
|
|
6289
7226
|
mapNoteToMemory: () => mapNoteToMemory,
|
|
7227
|
+
markUnfilled: () => markUnfilled,
|
|
6290
7228
|
matchBoundaryTerms: () => matchBoundaryTerms,
|
|
6291
7229
|
missingCounterparts: () => missingCounterparts,
|
|
6292
7230
|
needsRebase: () => needsRebase,
|
|
6293
7231
|
newProposalId: () => newProposalId,
|
|
6294
7232
|
noLifecycleReason: () => noLifecycleReason,
|
|
7233
|
+
ownEntry: () => ownEntry,
|
|
6295
7234
|
prepare: () => prepare,
|
|
6296
7235
|
prepareForMemory: () => prepareForMemory,
|
|
6297
7236
|
previewProposal: () => previewProposal,
|
|
@@ -6307,15 +7246,23 @@ __export(src_exports2, {
|
|
|
6307
7246
|
reconcile: () => reconcile,
|
|
6308
7247
|
redact: () => redact,
|
|
6309
7248
|
renderNewNote: () => renderNewNote,
|
|
7249
|
+
rescopeInput: () => rescopeInput,
|
|
6310
7250
|
resolveDetail: () => resolveDetail,
|
|
6311
7251
|
reversePatch: () => reversePatch,
|
|
6312
7252
|
reviseInput: () => reviseInput,
|
|
7253
|
+
ruleLane: () => ruleLane,
|
|
7254
|
+
rulePassage: () => rulePassage,
|
|
7255
|
+
ruleTextOf: () => ruleTextOf,
|
|
7256
|
+
ruleWidthFor: () => ruleWidthFor,
|
|
6313
7257
|
saveProposal: () => saveProposal,
|
|
6314
7258
|
saysNothingNew: () => saysNothingNew,
|
|
7259
|
+
scopeSpread: () => scopeSpread,
|
|
6315
7260
|
searchMemories: () => searchMemories,
|
|
6316
7261
|
semanticSourceFromVectors: () => semanticSourceFromVectors,
|
|
7262
|
+
splitRuleBudget: () => splitRuleBudget,
|
|
6317
7263
|
terms: () => terms,
|
|
6318
7264
|
transition: () => transition,
|
|
7265
|
+
unbindInput: () => unbindInput,
|
|
6319
7266
|
validateBoundaryTerm: () => validateBoundaryTerm,
|
|
6320
7267
|
variantsOf: () => variantsOf,
|
|
6321
7268
|
verifyPatch: () => verifyPatch,
|
|
@@ -6326,6 +7273,9 @@ var init_src3 = __esm({
|
|
|
6326
7273
|
"../../packages/memory-engine/src/index.ts"() {
|
|
6327
7274
|
"use strict";
|
|
6328
7275
|
init_schema();
|
|
7276
|
+
init_layout();
|
|
7277
|
+
init_rule_budget();
|
|
7278
|
+
init_rule_text();
|
|
6329
7279
|
init_boundary();
|
|
6330
7280
|
init_markdown_mapping();
|
|
6331
7281
|
init_build();
|
|
@@ -6333,6 +7283,11 @@ var init_src3 = __esm({
|
|
|
6333
7283
|
init_reconcile();
|
|
6334
7284
|
init_planner();
|
|
6335
7285
|
init_semantic();
|
|
7286
|
+
init_unfilled();
|
|
7287
|
+
init_setup_progress();
|
|
7288
|
+
init_query_prefix();
|
|
7289
|
+
init_base_templates();
|
|
7290
|
+
init_scope_spread();
|
|
6336
7291
|
init_conflicts();
|
|
6337
7292
|
init_search();
|
|
6338
7293
|
init_schema2();
|
|
@@ -8609,15 +9564,15 @@ function shouldExclude(relPath, isDir) {
|
|
|
8609
9564
|
if (EXCLUDE_EXTS.has(ext)) return true;
|
|
8610
9565
|
return false;
|
|
8611
9566
|
}
|
|
8612
|
-
async function walkDir(
|
|
8613
|
-
const entries = await readdir2(join8(
|
|
9567
|
+
async function walkDir(base2, relDir, collected) {
|
|
9568
|
+
const entries = await readdir2(join8(base2, relDir), { withFileTypes: true });
|
|
8614
9569
|
for (const entry of entries) {
|
|
8615
9570
|
const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
8616
9571
|
if (shouldExclude(rel, entry.isDirectory())) continue;
|
|
8617
9572
|
if (entry.isDirectory()) {
|
|
8618
|
-
await walkDir(
|
|
9573
|
+
await walkDir(base2, rel, collected);
|
|
8619
9574
|
} else if (entry.isFile()) {
|
|
8620
|
-
collected.push({ rel, abs: join8(
|
|
9575
|
+
collected.push({ rel, abs: join8(base2, rel) });
|
|
8621
9576
|
}
|
|
8622
9577
|
}
|
|
8623
9578
|
}
|
|
@@ -10023,6 +10978,7 @@ import { homedir as homedir4 } from "os";
|
|
|
10023
10978
|
import { join as join11 } from "path";
|
|
10024
10979
|
var PER_FILE_CAP = 16 * 1024;
|
|
10025
10980
|
var TOTAL_CAP = 48 * 1024;
|
|
10981
|
+
var TRUNCATION_RESERVE = 64;
|
|
10026
10982
|
async function pathExists3(p) {
|
|
10027
10983
|
try {
|
|
10028
10984
|
await access3(p);
|
|
@@ -10033,6 +10989,7 @@ async function pathExists3(p) {
|
|
|
10033
10989
|
}
|
|
10034
10990
|
function capContent(raw, cap) {
|
|
10035
10991
|
if (Buffer.byteLength(raw, "utf8") <= cap) return { content: raw, truncated: false };
|
|
10992
|
+
const fill = cap - TRUNCATION_RESERVE;
|
|
10036
10993
|
const lines = raw.split("\n");
|
|
10037
10994
|
let acc = 0;
|
|
10038
10995
|
let lastHeadingIdx = -1;
|
|
@@ -10041,7 +10998,7 @@ function capContent(raw, cap) {
|
|
|
10041
10998
|
const line = lines[i] ?? "";
|
|
10042
10999
|
const lineBytes = Buffer.byteLength(`${line}
|
|
10043
11000
|
`, "utf8");
|
|
10044
|
-
if (acc + lineBytes >
|
|
11001
|
+
if (acc + lineBytes > fill) {
|
|
10045
11002
|
cutIdx = i;
|
|
10046
11003
|
break;
|
|
10047
11004
|
}
|
|
@@ -10049,6 +11006,7 @@ function capContent(raw, cap) {
|
|
|
10049
11006
|
if (/^#{1,6}\s/.test(line)) lastHeadingIdx = i;
|
|
10050
11007
|
}
|
|
10051
11008
|
const cut = lastHeadingIdx > cutIdx / 2 ? lastHeadingIdx : cutIdx;
|
|
11009
|
+
if (cut === 0) return null;
|
|
10052
11010
|
const kept = lines.slice(0, cut).join("\n");
|
|
10053
11011
|
return {
|
|
10054
11012
|
content: `${kept}
|
|
@@ -10077,7 +11035,6 @@ async function readHarnessContext(cwd = process.cwd(), home = homedir4()) {
|
|
|
10077
11035
|
const files = [];
|
|
10078
11036
|
let totalBytes = 0;
|
|
10079
11037
|
for (const cand of candidates) {
|
|
10080
|
-
if (totalBytes >= TOTAL_CAP) break;
|
|
10081
11038
|
if (!await pathExists3(cand.path)) continue;
|
|
10082
11039
|
let raw;
|
|
10083
11040
|
try {
|
|
@@ -10086,7 +11043,9 @@ async function readHarnessContext(cwd = process.cwd(), home = homedir4()) {
|
|
|
10086
11043
|
continue;
|
|
10087
11044
|
}
|
|
10088
11045
|
const cap = Math.min(PER_FILE_CAP, TOTAL_CAP - totalBytes);
|
|
10089
|
-
const
|
|
11046
|
+
const capped2 = capContent(raw, cap);
|
|
11047
|
+
if (capped2 === null) break;
|
|
11048
|
+
const { content, truncated } = capped2;
|
|
10090
11049
|
totalBytes += Buffer.byteLength(content, "utf8");
|
|
10091
11050
|
files.push({
|
|
10092
11051
|
path: cand.display,
|
|
@@ -12743,9 +13702,9 @@ function assertNothingLost(before, after, action) {
|
|
|
12743
13702
|
});
|
|
12744
13703
|
}
|
|
12745
13704
|
}
|
|
12746
|
-
async function commit2(root,
|
|
13705
|
+
async function commit2(root, base2, next) {
|
|
12747
13706
|
const current = await readIgnoreFileState(root);
|
|
12748
|
-
if (current.hash !==
|
|
13707
|
+
if (current.hash !== base2.hash) {
|
|
12749
13708
|
return { ok: false, reason: "revision_conflict", current };
|
|
12750
13709
|
}
|
|
12751
13710
|
if (next === current.content) return { ok: true, content: next, changed: false };
|
|
@@ -12791,15 +13750,15 @@ function planRemoveIgnoreEntry(content, relPath) {
|
|
|
12791
13750
|
assertNothingLost(next, content, "un-excluding");
|
|
12792
13751
|
return { content: next, changed: true };
|
|
12793
13752
|
}
|
|
12794
|
-
async function addIgnoreEntry(root, relPath,
|
|
12795
|
-
const edit = planAddIgnoreEntry(
|
|
12796
|
-
if (!edit.changed) return { ok: true, content:
|
|
12797
|
-
return commit2(root,
|
|
13753
|
+
async function addIgnoreEntry(root, relPath, base2) {
|
|
13754
|
+
const edit = planAddIgnoreEntry(base2.content, relPath);
|
|
13755
|
+
if (!edit.changed) return { ok: true, content: base2.content, changed: false };
|
|
13756
|
+
return commit2(root, base2, edit.content);
|
|
12798
13757
|
}
|
|
12799
|
-
async function removeIgnoreEntry(root, relPath,
|
|
12800
|
-
const edit = planRemoveIgnoreEntry(
|
|
12801
|
-
if (!edit.changed) return { ok: true, content:
|
|
12802
|
-
return commit2(root,
|
|
13758
|
+
async function removeIgnoreEntry(root, relPath, base2) {
|
|
13759
|
+
const edit = planRemoveIgnoreEntry(base2.content, relPath);
|
|
13760
|
+
if (!edit.changed) return { ok: true, content: base2.content, changed: false };
|
|
13761
|
+
return commit2(root, base2, edit.content);
|
|
12803
13762
|
}
|
|
12804
13763
|
|
|
12805
13764
|
// src/commands/memory/exclude.ts
|
|
@@ -12845,8 +13804,8 @@ async function openVaultOrExplain(path2) {
|
|
|
12845
13804
|
// src/commands/memory/link.ts
|
|
12846
13805
|
init_brand();
|
|
12847
13806
|
function sameBasename(all, entry) {
|
|
12848
|
-
const
|
|
12849
|
-
return all.filter((p) => (p.split("/").pop() ?? "").normalize("NFC").toLowerCase() ===
|
|
13807
|
+
const base2 = (entry.split("/").pop() ?? entry).normalize("NFC").toLowerCase();
|
|
13808
|
+
return all.filter((p) => (p.split("/").pop() ?? "").normalize("NFC").toLowerCase() === base2);
|
|
12850
13809
|
}
|
|
12851
13810
|
function spreadAcrossFolders(rows, max) {
|
|
12852
13811
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -13110,7 +14069,7 @@ function excludeCommand() {
|
|
|
13110
14069
|
return new Command28("exclude").description("stop reading a note entirely \u2014 the note itself is not changed").argument("<path>", "vault-relative path of the note, e.g. decisions/launch-date.md").option("--yes", "skip the confirmation prompt").option("--vault <path>", "which linked vault the note is in").action(async (path2, opts) => {
|
|
13111
14070
|
const root = await resolveVaultRoot(opts.vault);
|
|
13112
14071
|
const target = await mustMatchAFile(root, path2);
|
|
13113
|
-
const
|
|
14072
|
+
const base2 = await readIgnoreFileState(root);
|
|
13114
14073
|
if (!opts.yes && isJsonMode()) {
|
|
13115
14074
|
throw memoryError(
|
|
13116
14075
|
"refusing to change what this vault reads without confirmation",
|
|
@@ -13134,7 +14093,7 @@ function excludeCommand() {
|
|
|
13134
14093
|
return;
|
|
13135
14094
|
}
|
|
13136
14095
|
}
|
|
13137
|
-
const result = await addIgnoreEntry(root, target,
|
|
14096
|
+
const result = await addIgnoreEntry(root, target, base2);
|
|
13138
14097
|
if (!result.ok) {
|
|
13139
14098
|
printDual({
|
|
13140
14099
|
json: {
|
|
@@ -13172,7 +14131,7 @@ function unexcludeCommand() {
|
|
|
13172
14131
|
return new Command28("unexclude").description("read a note again after excluding it").argument("<path>", "vault-relative path of the note").option("--yes", "skip the confirmation prompt").option("--vault <path>", "which linked vault the note is in").action(async (path2, opts) => {
|
|
13173
14132
|
const root = await resolveVaultRoot(opts.vault);
|
|
13174
14133
|
const target = path2.normalize("NFC");
|
|
13175
|
-
const
|
|
14134
|
+
const base2 = await readIgnoreFileState(root);
|
|
13176
14135
|
if (!opts.yes && isJsonMode()) {
|
|
13177
14136
|
throw memoryError(
|
|
13178
14137
|
"refusing to change what this vault reads without confirmation",
|
|
@@ -13195,7 +14154,7 @@ function unexcludeCommand() {
|
|
|
13195
14154
|
return;
|
|
13196
14155
|
}
|
|
13197
14156
|
}
|
|
13198
|
-
const result = await removeIgnoreEntry(root, target,
|
|
14157
|
+
const result = await removeIgnoreEntry(root, target, base2);
|
|
13199
14158
|
if (!result.ok) {
|
|
13200
14159
|
printDual({
|
|
13201
14160
|
json: {
|