hippo-memory 1.35.0 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +23 -1
- package/dist/audit.js.map +1 -1
- package/dist/autolearn.d.ts +16 -0
- package/dist/autolearn.d.ts.map +1 -1
- package/dist/autolearn.js +26 -0
- package/dist/autolearn.js.map +1 -1
- package/dist/capture.d.ts.map +1 -1
- package/dist/capture.js +303 -20
- package/dist/capture.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +48 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +14 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/src/audit.js +23 -1
- package/dist/src/audit.js.map +1 -1
- package/dist/src/autolearn.js +26 -0
- package/dist/src/autolearn.js.map +1 -1
- package/dist/src/capture.js +303 -20
- package/dist/src/capture.js.map +1 -1
- package/dist/src/cli.js +48 -8
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/server.js +14 -3
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,qBAAqB,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,qBAAqB,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AA8GD,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,CA6BjE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,CAWjE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ9D;AAMD,MAAM,MAAM,OAAO,GACf,UAAU,GACV,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,aAAa,GACb,aAAa,GACb,aAAa,GACb,SAAS,GACT,aAAa,GACb,aAAa,GACb,sBAAsB,GACtB,sBAAsB,GACtB,iBAAiB,GACjB,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,wBAAwB,GACxB,uCAAuC,GACvC,iCAAiC,GACjC,qCAAqC,GACrC,yCAAyC,GACzC,kCAAkC,GAClC,8BAA8B,GAC9B,iBAAiB,GACjB,oBAAoB,GACpB,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,gBAAgB,GAChB,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,GACf,eAAe,GACf,kBAAkB,GAClB,cAAc,GACd,cAAc,GACd,iBAAiB,GACjB,aAAa,GACb,sBAAsB,GACtB,yBAAyB,GACzB,qBAAqB,GACrB,sBAAsB,GACtB,yBAAyB,GACzB,qBAAqB,GACrB,WAAW,GACX,cAAc,GACd,gBAAgB,GAChB,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAMlB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoBD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CAWlF;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE,CAuCzF"}
|
package/dist/audit.js
CHANGED
|
@@ -80,9 +80,31 @@ function hasNoSpecificity(text) {
|
|
|
80
80
|
const words = text.toLowerCase().split(/\s+/);
|
|
81
81
|
const hasNumber = /\d/.test(text);
|
|
82
82
|
const hasProperNoun = /[A-Z][a-z]{2,}/.test(text);
|
|
83
|
+
// An ACRONYM is specificity too, and this test could not see one: the
|
|
84
|
+
// proper-noun pattern needs lowercase after the capital, so "PR", "CI",
|
|
85
|
+
// "DB", "API", "S3" - the densest domain tokens in a technical memory -
|
|
86
|
+
// all read as vague. Surfaced by DF2: clause-bounding correctly shortened
|
|
87
|
+
// "The rule is every PR needs two approvals, no exceptions." to "every PR
|
|
88
|
+
// needs two approvals", which then fell under the 40-char vagueness gate
|
|
89
|
+
// and was silently DROPPED - a rule that stored before this branch.
|
|
90
|
+
// ...but an acronym only signals specificity when it stands out AGAINST
|
|
91
|
+
// ordinary prose. Without the lowercase requirement, any shouted phrase
|
|
92
|
+
// qualifies: "FIXED SIGNALS" passed the gate while the identical
|
|
93
|
+
// "fixed signals" was correctly rejected, so capitalization alone bought a
|
|
94
|
+
// bypass - into auditMemory and includeRecent as well, where junk would
|
|
95
|
+
// then occupy recent-context slots. Codex P2, r8.
|
|
96
|
+
// CHAT acronyms are not domain signal. Admitting any all-caps token let
|
|
97
|
+
// "LGTM ship it", "TODO fix this thing", "FYI all done here" through a gate
|
|
98
|
+
// that correctly rejected them before - and this gate is shared, so the
|
|
99
|
+
// effect is retroactive: junk rows already in a user's store were filtered
|
|
100
|
+
// out of recent-context slots and would have started occupying them, and
|
|
101
|
+
// `hippo audit` would have stopped flagging them. Found at the ship gate.
|
|
102
|
+
const CHAT_ACRONYMS = /^(?:TODO|FYI|LGTM|IIRC|IMO|IMHO|FWIW|TBD|BTW|ASAP|AFAIK|WIP|NB|PS)$/;
|
|
103
|
+
const domainAcronyms = (text.match(/\b[A-Z]{2,6}\b/g) ?? []).filter(a => !CHAT_ACRONYMS.test(a));
|
|
104
|
+
const hasAcronym = domainAcronyms.length > 0 && /[a-z]/.test(text);
|
|
83
105
|
const hasPath = /[/\\.]/.test(text);
|
|
84
106
|
const hasCode = /[`_{}()\[\]]/.test(text);
|
|
85
|
-
if (hasNumber || hasProperNoun || hasPath || hasCode)
|
|
107
|
+
if (hasNumber || hasProperNoun || hasPath || hasCode || hasAcronym)
|
|
86
108
|
return false;
|
|
87
109
|
return words.length < 8 && VAGUE_ONLY.test(text);
|
|
88
110
|
}
|
package/dist/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/autolearn.d.ts
CHANGED
|
@@ -13,6 +13,22 @@ export declare function captureError(exitCode: number, stderr: string, command:
|
|
|
13
13
|
* Looks for fix:, revert:, bug:, error:, hotfix: commit messages.
|
|
14
14
|
*/
|
|
15
15
|
export declare function extractLessons(gitLog: string, customPatterns?: string[]): string[];
|
|
16
|
+
/**
|
|
17
|
+
* Split parsed lessons into ones worth storing and low-information ones.
|
|
18
|
+
*
|
|
19
|
+
* `extractLessons` is a published API surface (exported from src/index.ts)
|
|
20
|
+
* and does one job: parse a git log into candidate lesson strings. Adding a
|
|
21
|
+
* quality check inside it would break that contract and silently change
|
|
22
|
+
* what external callers get back. So parsing and admission are separate
|
|
23
|
+
* steps: this function is the write-path gate, called by each caller that
|
|
24
|
+
* actually stores a lesson, not by the parser itself.
|
|
25
|
+
*
|
|
26
|
+
* Order is preserved in both output arrays.
|
|
27
|
+
*/
|
|
28
|
+
export declare function partitionLessons(lessons: string[]): {
|
|
29
|
+
kept: string[];
|
|
30
|
+
dropped: string[];
|
|
31
|
+
};
|
|
16
32
|
/**
|
|
17
33
|
* Check if a substantially similar memory already exists.
|
|
18
34
|
* Returns true if overlap > threshold (default 0.7).
|
package/dist/autolearn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autolearn.d.ts","sourceRoot":"","sources":["../src/autolearn.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAuB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"autolearn.d.ts","sourceRoot":"","sources":["../src/autolearn.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAuB,MAAM,aAAa,CAAC;AAK/D;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,WAAW,CAoBb;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAsClF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAWzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,MAAM,GAAG,WAAW,EAAE,EAC1C,MAAM,EAAE,MAAM,EACd,SAAS,SAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAWT;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBzF;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAY9C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAS7D"}
|
package/dist/autolearn.js
CHANGED
|
@@ -6,6 +6,7 @@ import { execSync, execFileSync, spawn } from 'child_process';
|
|
|
6
6
|
import { createMemory, Layer } from './memory.js';
|
|
7
7
|
import { loadAllEntries } from './store.js';
|
|
8
8
|
import { textOverlap } from './search.js';
|
|
9
|
+
import { isContentWorthStoring } from './audit.js';
|
|
9
10
|
/**
|
|
10
11
|
* Create a MemoryEntry capturing a command failure.
|
|
11
12
|
* Content format: "Command '<cmd>' failed: <truncated stderr>"
|
|
@@ -68,6 +69,31 @@ export function extractLessons(gitLog, customPatterns) {
|
|
|
68
69
|
// Deduplicate exact matches at extraction time
|
|
69
70
|
return [...new Set(lessons)];
|
|
70
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Split parsed lessons into ones worth storing and low-information ones.
|
|
74
|
+
*
|
|
75
|
+
* `extractLessons` is a published API surface (exported from src/index.ts)
|
|
76
|
+
* and does one job: parse a git log into candidate lesson strings. Adding a
|
|
77
|
+
* quality check inside it would break that contract and silently change
|
|
78
|
+
* what external callers get back. So parsing and admission are separate
|
|
79
|
+
* steps: this function is the write-path gate, called by each caller that
|
|
80
|
+
* actually stores a lesson, not by the parser itself.
|
|
81
|
+
*
|
|
82
|
+
* Order is preserved in both output arrays.
|
|
83
|
+
*/
|
|
84
|
+
export function partitionLessons(lessons) {
|
|
85
|
+
const kept = [];
|
|
86
|
+
const dropped = [];
|
|
87
|
+
for (const lesson of lessons) {
|
|
88
|
+
if (isContentWorthStoring(lesson)) {
|
|
89
|
+
kept.push(lesson);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
dropped.push(lesson);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { kept, dropped };
|
|
96
|
+
}
|
|
71
97
|
/**
|
|
72
98
|
* Check if a substantially similar memory already exists.
|
|
73
99
|
* Returns true if overlap > threshold (default 0.7).
|
package/dist/autolearn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autolearn.js","sourceRoot":"","sources":["../src/autolearn.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAe,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"autolearn.js","sourceRoot":"","sources":["../src/autolearn.ts"],"names":[],"mappings":"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"}
|
package/dist/capture.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4BH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4BH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AA6YD;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAoC7D;AAuFD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,cAAc,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0BD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqFzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,IAAI,CAuCf;AAED,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,GACtB,IAAI,CAgBN;AAyPD,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,QAAa,CAAC;AAEjD,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ5E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA+B,GAAG,MAAM,CA4B5G;AA8DD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG1D;AAqOD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBhG"}
|
package/dist/capture.js
CHANGED
|
@@ -22,29 +22,51 @@ import { redactSecrets } from './secret-detect.js';
|
|
|
22
22
|
import { RejectedValueError, checkRejectionGuard } from './rejection.js';
|
|
23
23
|
import { openHippoDb, closeHippoDb } from './db.js';
|
|
24
24
|
// Sentence-level patterns
|
|
25
|
+
//
|
|
26
|
+
// T1 (DF2): each pattern now carries TWO capture groups — group 1 is the
|
|
27
|
+
// discriminating keyword (plus its trailing separator, verbatim), group 2 is
|
|
28
|
+
// the content that follows it. Previously only the after-keyword content was
|
|
29
|
+
// captured, so a negation like "never" / "must not" was discarded and a
|
|
30
|
+
// prohibition inverted into an instruction ("Never use X" stored as "use X").
|
|
31
|
+
// `extractFromPatterns` reassembles group1 + a clause-bounded group2 (T2, via
|
|
32
|
+
// `boundToClause` below) rather than reading a single fixed-width group —
|
|
33
|
+
// group 2's own reach is widened to {1,500} because the true stopping point
|
|
34
|
+
// is now found by content, not counted characters. Keeping the keyword in
|
|
35
|
+
// its own group (rather than folding it into one bigger capture) matters:
|
|
36
|
+
// `boundToClause` must scan for a clause boundary only in group 2, never in
|
|
37
|
+
// group 1 — several keywords end in their own colon ("error:", "rule:",
|
|
38
|
+
// "decision:") which is not a clause boundary in the prose sense and would
|
|
39
|
+
// wrongly truncate the capture down to just the keyword if scanned.
|
|
40
|
+
// `PREFERENCE_PATTERNS[0]` is the one exception — its two-capture-group
|
|
41
|
+
// shape means something different (two content spans either side of
|
|
42
|
+
// "instead of"/"over"/"not") and is a separate, backlogged defect (see
|
|
43
|
+
// docs/plans/2026-08-23-df2-capture-anchoring.md); left as-is.
|
|
25
44
|
const DECISION_PATTERNS = [
|
|
26
|
-
/(?:we(?:'ve| have)?|i(?:'ve| have)?|let's)\s+decid(?:ed|e)\s+(?:to\s+)?(.{
|
|
27
|
-
/(?:let's|we(?:'ll| will| should)?)\s+(?:go with|do|use|try|build|implement|switch to)\s+(.{
|
|
28
|
-
/(?:going|went)\s+with\s+(.{
|
|
29
|
-
/(?:the plan is|plan:)\s+(.{
|
|
30
|
-
/decision:\s*(.{
|
|
45
|
+
/(?:we(?:'ve| have)?|i(?:'ve| have)?|let's)\s+(decid(?:ed|e)\s+(?:to\s+)?)(.{1,500})/i,
|
|
46
|
+
/(?:let's|we(?:'ll| will| should)?)\s+((?:go with|do|use|try|build|implement|switch to)\s+)(.{1,500})/i,
|
|
47
|
+
/((?:going|went)\s+with\s+)(.{1,500})/i,
|
|
48
|
+
/((?:the plan is|plan:)\s+)(.{1,500})/i,
|
|
49
|
+
/(decision:\s*)(.{1,500})/i,
|
|
31
50
|
];
|
|
32
51
|
const RULE_PATTERNS = [
|
|
33
|
-
/(?:never|always|must(?:\s+not)?|do(?:n't| not)\s+ever)\s+(.{
|
|
34
|
-
/(?:the rule is|rule:)\s*(.{
|
|
35
|
-
/(?:important|critical|remember):\s*(.{
|
|
36
|
-
/(?:make sure|ensure)\s+(?:to\s+)?(.{
|
|
52
|
+
/((?:never|always|must(?:\s+not)?|do(?:n't| not)\s+ever)\s+)(.{1,500})/i,
|
|
53
|
+
/((?:the rule is|rule:)\s*)(.{1,500})/i,
|
|
54
|
+
/((?:important|critical|remember):\s*)(.{1,500})/i,
|
|
55
|
+
/((?:make sure|ensure)\s+(?:to\s+)?)(.{1,500})/i,
|
|
37
56
|
];
|
|
38
57
|
const ERROR_PATTERNS = [
|
|
39
|
-
/(?:error|bug|gotcha|watch out|careful|warning|caveat|trap):\s*(.{
|
|
40
|
-
/(?:this broke|this breaks|this will break|broke because)\s+(.{
|
|
41
|
-
/(?:the (?:issue|problem|fix) (?:is|was))\s+(.{
|
|
42
|
-
/(?:don't forget|easy to miss):\s*(.{
|
|
58
|
+
/((?:error|bug|gotcha|watch out|careful|warning|caveat|trap):\s*)(.{1,500})/i,
|
|
59
|
+
/((?:this broke|this breaks|this will break|broke because)\s+)(.{1,500})/i,
|
|
60
|
+
/((?:the (?:issue|problem|fix) (?:is|was))\s+)(.{1,500})/i,
|
|
61
|
+
/((?:don't forget|easy to miss):\s*)(.{1,500})/i,
|
|
43
62
|
];
|
|
63
|
+
// PREFERENCE_PATTERNS[0] keeps its pre-DF2 two-capture-group shape
|
|
64
|
+
// (match[1]-only, unbounded) — out of scope here, backlogged. See
|
|
65
|
+
// extractFromPatterns' reference check against this exact array element.
|
|
44
66
|
const PREFERENCE_PATTERNS = [
|
|
45
67
|
/(?:prefer|use)\s+(.{5,100})\s+(?:instead of|over|not)\s+(.{3,100})/i,
|
|
46
|
-
/(?:don't use|avoid|skip)\s+(.{
|
|
47
|
-
/(?:we(?:'re| are)\s+using|the stack is|we use)\s+(.{
|
|
68
|
+
/((?:don't use|avoid|skip)\s+)(.{1,500})/i,
|
|
69
|
+
/((?:we(?:'re| are)\s+using|the stack is|we use)\s+)(.{1,500})/i,
|
|
48
70
|
];
|
|
49
71
|
// Heading patterns that signal a following list of specs/requirements
|
|
50
72
|
const SPEC_HEADING_PATTERNS = [
|
|
@@ -61,19 +83,280 @@ function splitSentences(text) {
|
|
|
61
83
|
.map((s) => s.trim())
|
|
62
84
|
.filter((s) => s.length > 5);
|
|
63
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* T2 (DF2): bound a keyword+content capture to its clause instead of a fixed
|
|
88
|
+
* character count. `full` is `keywordPrefix + content` (already concatenated
|
|
89
|
+
* so the 200-char ceiling below applies to the whole stored string, not just
|
|
90
|
+
* the part after the keyword); `searchFrom` is `keywordPrefix.length`, so the
|
|
91
|
+
* clause/terminator scan only ever looks INSIDE `content` — several keywords
|
|
92
|
+
* end in their own colon ("error:", "rule:", "decision:") which must never
|
|
93
|
+
* be mistaken for a clause boundary in the prose that follows.
|
|
94
|
+
*
|
|
95
|
+
* Stops at the first `,`/`;`/`:` followed by whitespace, or at a sentence
|
|
96
|
+
* terminator `[.!?]` followed by whitespace or end-of-string — whichever
|
|
97
|
+
* comes first — and never past `maxLen` chars total.
|
|
98
|
+
*
|
|
99
|
+
* The whitespace requirement on the terminator is load-bearing: a bare
|
|
100
|
+
* `[.!?]` would split inside a token like `.env` / `capture.ts` / `v1.35.0`,
|
|
101
|
+
* turning a full clause into a fragment that then fails the write gate and
|
|
102
|
+
* is silently dropped (measured in the plan). The `maxLen` ceiling is also
|
|
103
|
+
* load-bearing: without it, a clause-free span can run past the 500-char
|
|
104
|
+
* gate in `extractFromPatterns` and the whole match is dropped, where today
|
|
105
|
+
* it is truncated and stored.
|
|
106
|
+
*/
|
|
107
|
+
/**
|
|
108
|
+
* Does a plausible CLOSING single quote appear after `from`? Mirror of the
|
|
109
|
+
* opener rule in `boundToClause`: a closer sits tight against the literal it
|
|
110
|
+
* ends (non-whitespace before) and is followed by whitespace, punctuation, or
|
|
111
|
+
* end-of-string - never by a letter, which is what makes "user's" an
|
|
112
|
+
* apostrophe rather than a partner.
|
|
113
|
+
*/
|
|
114
|
+
function isLetterOrDigit(ch) {
|
|
115
|
+
return ch !== undefined && /[\p{L}\p{N}]/u.test(ch);
|
|
116
|
+
}
|
|
117
|
+
function lastCloserIndex(full) {
|
|
118
|
+
// ONE pass, not one per apostrophe. The previous shape rescanned the whole
|
|
119
|
+
// remaining suffix at every boundary apostrophe, so a transcript full of
|
|
120
|
+
// elisions ("keep 'em", "wait 'til", ...) made extraction quadratic and
|
|
121
|
+
// could stall a moderately sized capture. Codex P2, r7.
|
|
122
|
+
//
|
|
123
|
+
// A quote CLOSES THE SIDE IT IS TIGHT AGAINST. The test needs both
|
|
124
|
+
// neighbours, and one round proved that empirically: these two have the
|
|
125
|
+
// same following character and opposite roles -
|
|
126
|
+
// "preserve 'a, b'-style" next '-' -> CLOSER, content on the left
|
|
127
|
+
// "then run '--force," next '-' -> OPENER, content on the right
|
|
128
|
+
// so no forward-only rule can separate them. An earlier revision tried
|
|
129
|
+
// exactly that and broke in both directions at once (codex P1+P2, r10):
|
|
130
|
+
// it missed closers before token-joining punctuation and accepted
|
|
131
|
+
// "'.env" as a closer because a dot happened to be in its class.
|
|
132
|
+
//
|
|
133
|
+
// never a closer next is a letter/digit "user's", "keep 'em"
|
|
134
|
+
// closer prev is non-whitespace "'a, b' to", "'a, b'-style"
|
|
135
|
+
// closer next is whitespace or end "preserve 'a, b ' exactly"
|
|
136
|
+
// closer next is clause punctuation "preserve 'a, b ', then"
|
|
137
|
+
// that itself ends the token
|
|
138
|
+
//
|
|
139
|
+
// The last clause is what separates ", " from ".env": a dot followed by a
|
|
140
|
+
// letter joins a filename, a dot followed by space ends a sentence.
|
|
141
|
+
for (let j = full.length - 1; j >= 0; j--) {
|
|
142
|
+
if (full[j] !== "'")
|
|
143
|
+
continue;
|
|
144
|
+
const prev = full[j - 1];
|
|
145
|
+
const next = full[j + 1];
|
|
146
|
+
if (isLetterOrDigit(next))
|
|
147
|
+
continue;
|
|
148
|
+
// "tight against content" excludes an OPENING delimiter: in
|
|
149
|
+
// "call parse('--force" the paren is non-whitespace but the quote after
|
|
150
|
+
// it is an opener, and treating it as a closer let an earlier elision
|
|
151
|
+
// pair across the clause boundary. Codex P2, r11.
|
|
152
|
+
const tightBefore = prev !== undefined && !/[\s([{]/.test(prev);
|
|
153
|
+
const endsAfter = next === undefined || /\s/.test(next);
|
|
154
|
+
// Punctuation splits in two, and this is the fact the last three
|
|
155
|
+
// revisions kept rediscovering piecemeal:
|
|
156
|
+
// , ; : ! ? ) ] } never join tokens - they end the literal whatever
|
|
157
|
+
// follows, so "'echo a, b ';then" closes at the ;
|
|
158
|
+
// . - _ / @ # DO join tokens - "'.env" and "'--force" continue a
|
|
159
|
+
// filename or flag, so these only close when trailed
|
|
160
|
+
// by whitespace
|
|
161
|
+
const afterNext = full[j + 2];
|
|
162
|
+
const closesRegardless = next !== undefined && /[,;:!?)\]}]/.test(next);
|
|
163
|
+
const joinerThenSpace = next !== undefined && /[.\-_/@#]/.test(next) &&
|
|
164
|
+
(afterNext === undefined || /\s/.test(afterNext));
|
|
165
|
+
if (tightBefore || endsAfter || closesRegardless || joinerThenSpace)
|
|
166
|
+
return j;
|
|
167
|
+
}
|
|
168
|
+
return -1;
|
|
169
|
+
}
|
|
170
|
+
function boundToClause(full, searchFrom, maxLen = 200) {
|
|
171
|
+
// Scan for the first PROSE clause boundary after `searchFrom`.
|
|
172
|
+
//
|
|
173
|
+
// Depth-awareness is not a nicety here: hippo memories are full of code, and
|
|
174
|
+
// a naive scan reintroduces the exact fragment defect this whole change
|
|
175
|
+
// exists to remove. Measured before this guard existed:
|
|
176
|
+
// "Always call build(x, y) before deploy." -> "Always call build(x"
|
|
177
|
+
// "Never pass {a: 1, b: 2} to the writer." -> "Never pass {a"
|
|
178
|
+
// Both then PASS the write gate, because they contain code punctuation and
|
|
179
|
+
// so read as "specific" — a malformed fragment stored with high confidence.
|
|
180
|
+
// Codex review finding (P1) on this branch.
|
|
181
|
+
//
|
|
182
|
+
// So: a separator only ends the clause at bracket depth zero and outside
|
|
183
|
+
// quotes. Unbalanced closers are tolerated (depth floors at 0) because
|
|
184
|
+
// captured text often starts mid-expression.
|
|
185
|
+
const lastCloser = lastCloserIndex(full);
|
|
186
|
+
let depth = 0;
|
|
187
|
+
let quote = null;
|
|
188
|
+
let cutEnd = full.length;
|
|
189
|
+
for (let i = searchFrom; i < full.length; i++) {
|
|
190
|
+
const ch = full[i];
|
|
191
|
+
if (quote) {
|
|
192
|
+
// Closing uses the SAME shape test as opening. This was asymmetric:
|
|
193
|
+
// twelve rounds went into deciding when a quote OPENS a literal, while
|
|
194
|
+
// the close accepted any bare "'" - so the apostrophe in a possessive
|
|
195
|
+
// INSIDE a literal closed it early:
|
|
196
|
+
// "Always pass 'user's a, b list' to the parser."
|
|
197
|
+
// -> "Always pass 'user's a" (master kept the whole literal)
|
|
198
|
+
// a mid-literal fragment that then PASSES the write gate, which is
|
|
199
|
+
// precisely the defect this branch exists to remove. Found by the
|
|
200
|
+
// ship-gate review after every earlier gate missed it.
|
|
201
|
+
if (ch === quote && (quote !== "'" || !isLetterOrDigit(full[i + 1]))) {
|
|
202
|
+
quote = null;
|
|
203
|
+
}
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
// Quote handling has to tell an APOSTROPHE from a single-quoted
|
|
207
|
+
// LITERAL, because getting either wrong reintroduces the fragment
|
|
208
|
+
// defect this change exists to remove, and both fragments PASS the
|
|
209
|
+
// write gate (code punctuation reads as "specific"):
|
|
210
|
+
// treat every ' as a quote -> "Always ensure it's enabled, then
|
|
211
|
+
// restart..." never leaves quote mode, bounding disabled entirely
|
|
212
|
+
// treat no ' as a quote -> "Always pass 'a, b' to the parser."
|
|
213
|
+
// cuts at the comma and stores "Always pass 'a"
|
|
214
|
+
// Both were codex P1s on this branch, in consecutive rounds.
|
|
215
|
+
//
|
|
216
|
+
// Discriminator: a ' OPENS a literal only at a word boundary - preceded
|
|
217
|
+
// by start/whitespace/open-bracket AND followed by non-whitespace. An
|
|
218
|
+
// in-word apostrophe ("it's", "user's") has letters on both sides and is
|
|
219
|
+
// just a character.
|
|
220
|
+
if (ch === '"' || ch === '`') {
|
|
221
|
+
quote = ch;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (ch === "'") {
|
|
225
|
+
const prev = i > 0 ? full[i - 1] : undefined;
|
|
226
|
+
const next = full[i + 1];
|
|
227
|
+
const atBoundary = (prev === undefined || /[\s([{]/.test(prev)) &&
|
|
228
|
+
next !== undefined && !/\s/.test(next);
|
|
229
|
+
// Pairing is VERIFIED, not assumed. A word-boundary test alone still
|
|
230
|
+
// opens quote mode on elided forms ("keep 'em", "wait 'til"), which
|
|
231
|
+
// have no closer, so the scanner never leaves quote mode and bounding
|
|
232
|
+
// is disabled for the rest of the capture. Requiring an actual closing
|
|
233
|
+
// quote later in the string replaces a guess with a checkable fact -
|
|
234
|
+
// an elided form simply has no partner. Codex P2, this round.
|
|
235
|
+
// ...and the partner must LOOK like a closer, not merely be another
|
|
236
|
+
// apostrophe. Distance cannot separate the two cases - both put a `'`
|
|
237
|
+
// far downstream:
|
|
238
|
+
// "Always pass '<600-char literal>' to the parser" -> the far ' IS
|
|
239
|
+
// the closer, and pairing must succeed
|
|
240
|
+
// "keep 'em enabled, then <520 chars> check user's config" -> the far
|
|
241
|
+
// ' is in-word, and pairing against it re-opens quote mode on the
|
|
242
|
+
// elision, disabling bounding for the rest of the capture
|
|
243
|
+
// So apply the SAME shape rule already used to open a literal, mirrored:
|
|
244
|
+
// a closer has non-whitespace before it and whitespace/punctuation (not
|
|
245
|
+
// a letter) after. "user's" fails it on both counts. Codex P2, r6.
|
|
246
|
+
if (atBoundary && lastCloser > i) {
|
|
247
|
+
quote = ch;
|
|
248
|
+
}
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (ch === '(' || ch === '[' || ch === '{') {
|
|
252
|
+
depth++;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (ch === ')' || ch === ']' || ch === '}') {
|
|
256
|
+
if (depth > 0)
|
|
257
|
+
depth--;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (depth > 0)
|
|
261
|
+
continue;
|
|
262
|
+
const next = full[i + 1];
|
|
263
|
+
// Prose clause separator: , ; : followed by whitespace.
|
|
264
|
+
if ((ch === ',' || ch === ';' || ch === ':') && next !== undefined && /\s/.test(next)) {
|
|
265
|
+
cutEnd = i;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
// Sentence terminator, but only when followed by whitespace or end — a
|
|
269
|
+
// bare [.!?] splits inside .env, capture.ts, v1.35.0.
|
|
270
|
+
if ((ch === '.' || ch === '!' || ch === '?') && (next === undefined || /\s/.test(next))) {
|
|
271
|
+
cutEnd = i + 1;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
let bounded = full.slice(0, cutEnd);
|
|
276
|
+
if (bounded.length > maxLen)
|
|
277
|
+
bounded = bounded.slice(0, maxLen);
|
|
278
|
+
return bounded;
|
|
279
|
+
}
|
|
64
280
|
function cleanExtract(raw) {
|
|
65
|
-
|
|
281
|
+
let content = raw
|
|
66
282
|
.replace(/^[:\s-]+/, '')
|
|
67
283
|
.replace(/[.!?,;:\s]+$/, '')
|
|
68
284
|
.trim();
|
|
285
|
+
// T2 trailing cleanup: clause-bounding can cut inside a parenthetical and
|
|
286
|
+
// leave an unmatched trailing ')' (e.g. "...(two had never got entries),"
|
|
287
|
+
// bounds to "never got entries)"). Strip a trailing ')' ONLY while closes
|
|
288
|
+
// outnumber opens in the string so far — a balanced parenthetical like
|
|
289
|
+
// "always run the suite (twice)" must be left intact.
|
|
290
|
+
while (content.endsWith(')')) {
|
|
291
|
+
const opens = (content.match(/\(/g) ?? []).length;
|
|
292
|
+
const closes = (content.match(/\)/g) ?? []).length;
|
|
293
|
+
if (closes <= opens)
|
|
294
|
+
break;
|
|
295
|
+
content = content
|
|
296
|
+
.slice(0, -1)
|
|
297
|
+
.replace(/[.!?,;:\s]+$/, '')
|
|
298
|
+
.trim();
|
|
299
|
+
}
|
|
300
|
+
return content;
|
|
69
301
|
}
|
|
70
302
|
function extractFromPatterns(sentence, patterns, category, tag) {
|
|
71
303
|
for (const pat of patterns) {
|
|
72
|
-
|
|
304
|
+
// `d` gives per-group offsets; see the contentStart comment below.
|
|
305
|
+
const dpat = pat.flags.includes('d') ? pat : new RegExp(pat.source, pat.flags + 'd');
|
|
306
|
+
const match = dpat.exec(sentence);
|
|
73
307
|
if (match) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
308
|
+
let bounded;
|
|
309
|
+
if (pat === PREFERENCE_PATTERNS[0]) {
|
|
310
|
+
// PREFERENCE_PATTERNS[0] is the one pattern left out of T1/T2 (see
|
|
311
|
+
// comment at its definition) — its match[1] keeps its pre-DF2,
|
|
312
|
+
// unbounded shape rather than going through clause-bounding.
|
|
313
|
+
bounded = match[1] ?? match[0];
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
// group1 = keyword + separator (verbatim, never clause-bounded);
|
|
317
|
+
// group2 = the content that follows it (clause-bounded below).
|
|
318
|
+
//
|
|
319
|
+
// T1 preserves the keyword only when it carries SEMANTIC SIGN — a
|
|
320
|
+
// negation or modality ("never", "must not", "do not ever",
|
|
321
|
+
// "always"). Dropping those inverts the meaning, which is the whole
|
|
322
|
+
// point of T1. A LABEL keyword ("decision:", "rule:", "error:",
|
|
323
|
+
// "important:") carries no sign: it only names the category, which
|
|
324
|
+
// is already recorded in `category`/`tags`, so prefixing it onto the
|
|
325
|
+
// content is duplication that also breaks value-keyed matching
|
|
326
|
+
// (AT1's rejected-value digest hashes the bare content).
|
|
327
|
+
// Discriminator: a label ends in its own colon, or is a "the X is"
|
|
328
|
+
// phrase.
|
|
329
|
+
const rawPrefix = match[1] ?? '';
|
|
330
|
+
// ONLY colon-terminated labels are dropped. Dropping "the X is/was"
|
|
331
|
+
// too left the residue starting with "to ", which isFragment then
|
|
332
|
+
// rejected outright - so "The plan is to ship on Friday" and "The fix
|
|
333
|
+
// was to bump the pool timeout" stored NOTHING, where every prior
|
|
334
|
+
// version stored them. Silent loss on two of the highest-traffic
|
|
335
|
+
// patterns, and invisible: an absent memory leaves no trace. The AT1
|
|
336
|
+
// rejected-value evidence only ever involved colon labels
|
|
337
|
+
// ("decision: "), so the narrower rule keeps that guarantee.
|
|
338
|
+
const isLabelPrefix = /:\s*$/.test(rawPrefix);
|
|
339
|
+
const keywordPrefix = isLabelPrefix ? '' : rawPrefix;
|
|
340
|
+
// Scan the UNTRUNCATED remainder, not match[2]. The patterns cap
|
|
341
|
+
// their content group at 500 chars, so a quoted literal whose closer
|
|
342
|
+
// sits past that point had no visible partner and the pairing check
|
|
343
|
+
// read the opener as prose - cutting inside the literal. That was a
|
|
344
|
+
// blindness built into the scanner's INPUT, not a bad predicate, so
|
|
345
|
+
// no further predicate could have fixed it. boundToClause already
|
|
346
|
+
// caps its OUTPUT at maxLen, so widening the input costs nothing and
|
|
347
|
+
// makes pairing decidable on the whole sentence. Codex P2, round 5.
|
|
348
|
+
// Group 2's REAL offset, read from the regex engine. Deriving it as
|
|
349
|
+
// `match.index + rawPrefix.length` assumes group 1 starts the match,
|
|
350
|
+
// but DECISION_PATTERNS carry an uncaptured subject ("we ", "let's ")
|
|
351
|
+
// ahead of it - so the offset landed inside the keyword and the
|
|
352
|
+
// widened slice duplicated text: "We decided to pin..." stored as
|
|
353
|
+
// "decided to to pin...". Real corruption of the commonest decision
|
|
354
|
+
// capture, shipped in the previous commit. Codex P1, r6.
|
|
355
|
+
const contentStart = match.indices?.[2]?.[0] ?? -1;
|
|
356
|
+
const afterKeyword = contentStart >= 0 ? sentence.slice(contentStart) : (match[2] ?? match[0]);
|
|
357
|
+
bounded = boundToClause(keywordPrefix + afterKeyword, keywordPrefix.length);
|
|
358
|
+
}
|
|
359
|
+
const content = cleanExtract(bounded);
|
|
77
360
|
if (content.length >= 8 && content.length <= 500) {
|
|
78
361
|
return { content, category, tags: [tag, 'captured'] };
|
|
79
362
|
}
|