memgineering 0.23.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/assets/MEMGINEERING.md +1 -1
- package/dist/index.js +61 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,32 @@ language the reader wants. The bilingual rule the monorepo applies to
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.23.1] — 2026-09-11
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **The rules a hook shows now include the sentence that says what to do.**
|
|
19
|
+
`memgineering guard` quoted each rule's `summary`, which is the note's text
|
|
20
|
+
cut at 200 characters — so a rule long enough to describe a problem before
|
|
21
|
+
prescribing an answer arrived with the answer removed. Measured across 24
|
|
22
|
+
sessions: of six rules planted as global rules, five were cut immediately
|
|
23
|
+
before their prescription, and every session holding one of them walked into
|
|
24
|
+
the trap its own rule described. The hook now quotes the rule as written, and
|
|
25
|
+
when it still has to shorten one it elides the MIDDLE, keeping the opening and
|
|
26
|
+
the closing instruction.
|
|
27
|
+
- **A short list of rules is now read further than a long one.** The width is a
|
|
28
|
+
budget shared across the whole block rather than a fixed cap per line, so two
|
|
29
|
+
standing decisions arrive in full where ten are abbreviated. Ten rules cost
|
|
30
|
+
exactly what ten rules cost before — nothing here prints more than it used to.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **A hosted brain sends the rule, not just the card.** `POST /rules` gained a
|
|
35
|
+
`text` field carrying the rule as written; a client older than this ignores it
|
|
36
|
+
and keeps rendering `summary`, and a server older than this makes the new
|
|
37
|
+
client fall back to `summary` as well. Deploy the server first to get the
|
|
38
|
+
benefit; neither order breaks anything.
|
|
39
|
+
|
|
14
40
|
## [0.23.0] — 2026-09-09
|
|
15
41
|
|
|
16
42
|
### Added
|
package/assets/MEMGINEERING.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: memgineering
|
|
3
3
|
description: Use whenever the user refers to something they told you before, asks what was decided, tells you something worth keeping, or settles something that should hold next time. The memory lives in their own folder and outlives this session; check it before answering from guesswork, and write to it when you learn something durable.
|
|
4
4
|
type: skill
|
|
5
|
-
version: 0.23.
|
|
5
|
+
version: 0.23.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# memgineering
|
package/dist/index.js
CHANGED
|
@@ -497,6 +497,52 @@ var init_rule_budget = __esm({
|
|
|
497
497
|
}
|
|
498
498
|
});
|
|
499
499
|
|
|
500
|
+
// ../../packages/memory-engine/src/rule-text.ts
|
|
501
|
+
function ruleTextOf(entry) {
|
|
502
|
+
const intro = (entry.chunks ?? []).find((chunk) => chunk.label === null)?.text.trim();
|
|
503
|
+
if (intro !== void 0 && intro !== "") return intro;
|
|
504
|
+
return entry.memory.summary ?? entry.memory.title;
|
|
505
|
+
}
|
|
506
|
+
function ruleWidthFor(count) {
|
|
507
|
+
if (count <= 0) return RULE_WIDTH_MIN;
|
|
508
|
+
const share = Math.floor(RULE_BLOCK_BUDGET / count);
|
|
509
|
+
return Math.min(RULE_WIDTH_MAX, Math.max(RULE_WIDTH_MIN, share));
|
|
510
|
+
}
|
|
511
|
+
function rulePassage(text, max) {
|
|
512
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
513
|
+
const chars = [...flat];
|
|
514
|
+
if (chars.length <= max) return flat;
|
|
515
|
+
if (max <= 1) return "\u2026";
|
|
516
|
+
const budget = max - 1;
|
|
517
|
+
if (budget < 2) return `${chars.slice(0, budget).join("")}\u2026`;
|
|
518
|
+
const tailBudget = Math.min(budget - 1, Math.max(1, Math.floor(budget * 0.6)));
|
|
519
|
+
const tail = [...trailingSentences(flat, tailBudget)];
|
|
520
|
+
const head = chars.slice(0, budget - tail.length).join("").trimEnd();
|
|
521
|
+
return `${head}\u2026${tail.join("")}`;
|
|
522
|
+
}
|
|
523
|
+
function trailingSentences(flat, budget) {
|
|
524
|
+
const starts = [...flat.matchAll(/[.!?。!?](?=\s)/g)].map(
|
|
525
|
+
(match) => match.index + match[0].length
|
|
526
|
+
);
|
|
527
|
+
let best = null;
|
|
528
|
+
for (let i = starts.length - 1; i >= 0; i -= 1) {
|
|
529
|
+
const candidate = flat.slice(starts[i]).trim();
|
|
530
|
+
if ([...candidate].length > budget) break;
|
|
531
|
+
if (candidate !== "") best = candidate;
|
|
532
|
+
}
|
|
533
|
+
if (best !== null) return best;
|
|
534
|
+
return [...flat].slice(-budget).join("");
|
|
535
|
+
}
|
|
536
|
+
var RULE_WIDTH_MIN, RULE_WIDTH_MAX, RULE_BLOCK_BUDGET;
|
|
537
|
+
var init_rule_text = __esm({
|
|
538
|
+
"../../packages/memory-engine/src/rule-text.ts"() {
|
|
539
|
+
"use strict";
|
|
540
|
+
RULE_WIDTH_MIN = 200;
|
|
541
|
+
RULE_WIDTH_MAX = 600;
|
|
542
|
+
RULE_BLOCK_BUDGET = RULE_WIDTH_MIN * 10;
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
500
546
|
// ../../packages/memory-engine/src/boundary.ts
|
|
501
547
|
function normalizeForMatch(value) {
|
|
502
548
|
return value.normalize("NFC").replace(ZERO_WIDTH, "").replace(WHITESPACE_RUN, " ").trim();
|
|
@@ -4230,6 +4276,7 @@ var init_src = __esm({
|
|
|
4230
4276
|
init_schema();
|
|
4231
4277
|
init_layout();
|
|
4232
4278
|
init_rule_budget();
|
|
4279
|
+
init_rule_text();
|
|
4233
4280
|
init_boundary();
|
|
4234
4281
|
init_markdown_mapping();
|
|
4235
4282
|
init_build();
|
|
@@ -15797,26 +15844,31 @@ async function collectRules(vault, contextDir, now = /* @__PURE__ */ new Date())
|
|
|
15797
15844
|
...unreachableDefault ? { unreachableDefault } : {}
|
|
15798
15845
|
};
|
|
15799
15846
|
}
|
|
15800
|
-
var RULE_WIDTH =
|
|
15847
|
+
var RULE_WIDTH = RULE_WIDTH_MIN;
|
|
15801
15848
|
function renderRuleLine(text, width = RULE_WIDTH) {
|
|
15802
|
-
return quoteBlock(
|
|
15849
|
+
return quoteBlock(rulePassage(oneLineWhole(text), width));
|
|
15803
15850
|
}
|
|
15804
|
-
function renderRuleLines(rules) {
|
|
15805
|
-
return rules.map(({ entry }) => renderRuleLine(entry
|
|
15851
|
+
function renderRuleLines(rules, width = ruleWidthFor(rules.length)) {
|
|
15852
|
+
return rules.map(({ entry }) => renderRuleLine(ruleTextOf(entry), width));
|
|
15806
15853
|
}
|
|
15807
15854
|
function renderRuleGroups(rules, project) {
|
|
15808
15855
|
const globals = rules.filter((rule) => rule.lane === "global");
|
|
15809
15856
|
const scoped = rules.filter((rule) => rule.lane === "project");
|
|
15857
|
+
const width = ruleWidthFor(rules.length);
|
|
15810
15858
|
const out = [];
|
|
15811
15859
|
if (globals.length > 0 && scoped.length > 0) {
|
|
15812
|
-
out.push("Everywhere:", ...renderRuleLines(globals), "");
|
|
15813
|
-
out.push(
|
|
15860
|
+
out.push("Everywhere:", ...renderRuleLines(globals, width), "");
|
|
15861
|
+
out.push(
|
|
15862
|
+
`In ${oneLine(project ?? "this project", WIDTH.title)}:`,
|
|
15863
|
+
...renderRuleLines(scoped, width)
|
|
15864
|
+
);
|
|
15814
15865
|
return out;
|
|
15815
15866
|
}
|
|
15816
|
-
return renderRuleLines(rules);
|
|
15867
|
+
return renderRuleLines(rules, width);
|
|
15817
15868
|
}
|
|
15818
15869
|
|
|
15819
15870
|
// src/commands/guard.ts
|
|
15871
|
+
init_src();
|
|
15820
15872
|
init_deadline();
|
|
15821
15873
|
init_cloud_brain();
|
|
15822
15874
|
function guardCommand() {
|
|
@@ -16015,7 +16067,8 @@ async function hostedRuleLines(where, contextDir) {
|
|
|
16015
16067
|
return { lines: grouped, total };
|
|
16016
16068
|
}
|
|
16017
16069
|
function groupHostedLines(rules, project) {
|
|
16018
|
-
const
|
|
16070
|
+
const width = ruleWidthFor(rules.length);
|
|
16071
|
+
const line = (r) => renderRuleLine(r.text ?? r.summary ?? r.title, width);
|
|
16019
16072
|
const globals = rules.filter((r) => r.lane === "global");
|
|
16020
16073
|
const scoped = rules.filter((r) => r.lane === "project");
|
|
16021
16074
|
if (globals.length === 0 || scoped.length === 0) return rules.map(line);
|
package/package.json
CHANGED