@seanhogg/builderforce-memory 2026.10.23 → 2026.10.25

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.
Files changed (60) hide show
  1. package/dist/handoff/index.d.ts +1 -0
  2. package/dist/handoff/index.d.ts.map +1 -1
  3. package/dist/handoff/index.js +1 -0
  4. package/dist/handoff/index.js.map +1 -1
  5. package/dist/handoff/pack.d.ts.map +1 -1
  6. package/dist/handoff/pack.js +30 -3
  7. package/dist/handoff/pack.js.map +1 -1
  8. package/dist/handoff/volatile.d.ts +32 -0
  9. package/dist/handoff/volatile.d.ts.map +1 -0
  10. package/dist/handoff/volatile.js +42 -0
  11. package/dist/handoff/volatile.js.map +1 -0
  12. package/dist/working/consolidate.d.ts +39 -0
  13. package/dist/working/consolidate.d.ts.map +1 -0
  14. package/dist/working/consolidate.js +179 -0
  15. package/dist/working/consolidate.js.map +1 -0
  16. package/dist/working/consolidationMarker.d.ts +75 -0
  17. package/dist/working/consolidationMarker.d.ts.map +1 -0
  18. package/dist/working/consolidationMarker.js +104 -0
  19. package/dist/working/consolidationMarker.js.map +1 -0
  20. package/dist/working/index.d.ts +35 -0
  21. package/dist/working/index.d.ts.map +1 -0
  22. package/dist/working/index.js +31 -0
  23. package/dist/working/index.js.map +1 -0
  24. package/dist/working/rank.d.ts +7 -0
  25. package/dist/working/rank.d.ts.map +1 -0
  26. package/dist/working/rank.js +12 -0
  27. package/dist/working/rank.js.map +1 -0
  28. package/dist/working/summary.d.ts +31 -0
  29. package/dist/working/summary.d.ts.map +1 -0
  30. package/dist/working/summary.js +48 -0
  31. package/dist/working/summary.js.map +1 -0
  32. package/dist/working/transcript.d.ts +137 -0
  33. package/dist/working/transcript.d.ts.map +1 -0
  34. package/dist/working/transcript.js +243 -0
  35. package/dist/working/transcript.js.map +1 -0
  36. package/dist/working/types.d.ts +33 -0
  37. package/dist/working/types.d.ts.map +1 -0
  38. package/dist/working/types.js +5 -0
  39. package/dist/working/types.js.map +1 -0
  40. package/dist/working/workingMemory.d.ts +45 -0
  41. package/dist/working/workingMemory.d.ts.map +1 -0
  42. package/dist/working/workingMemory.js +103 -0
  43. package/dist/working/workingMemory.js.map +1 -0
  44. package/package.json +7 -3
  45. package/src/handoff/handoff.test.ts +28 -1
  46. package/src/handoff/index.ts +1 -0
  47. package/src/handoff/pack.ts +30 -4
  48. package/src/handoff/volatile.ts +46 -0
  49. package/src/working/consolidate.ts +181 -0
  50. package/src/working/consolidationMarker.test.ts +95 -0
  51. package/src/working/consolidationMarker.ts +115 -0
  52. package/src/working/index.ts +59 -0
  53. package/src/working/rank.ts +10 -0
  54. package/src/working/summary.test.ts +51 -0
  55. package/src/working/summary.ts +68 -0
  56. package/src/working/transcript.test.ts +125 -0
  57. package/src/working/transcript.ts +291 -0
  58. package/src/working/types.ts +32 -0
  59. package/src/working/working.test.ts +120 -0
  60. package/src/working/workingMemory.ts +103 -0
@@ -14,5 +14,6 @@
14
14
  export { packHandoff } from './pack.js';
15
15
  export { handoffBudget, defaultEstimateTokens, messageTokens, tokensOf } from './budget.js';
16
16
  export { handoffLine, elisionMarker } from './note.js';
17
+ export { VOLATILE_TAIL_TAG, volatileTail, isVolatileTail, isVolatileContent } from './volatile.js';
17
18
  export type { HandoffMessage, HandoffPackInput, HandoffPack, HandoffBudgetInput, TokenEstimator, } from './types.js';
18
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handoff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handoff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACnG,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -14,4 +14,5 @@
14
14
  export { packHandoff } from './pack.js';
15
15
  export { handoffBudget, defaultEstimateTokens, messageTokens, tokensOf } from './budget.js';
16
16
  export { handoffLine, elisionMarker } from './note.js';
17
+ export { VOLATILE_TAIL_TAG, volatileTail, isVolatileTail, isVolatileContent } from './volatile.js';
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handoff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handoff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/handoff/pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAkB,WAAW,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AA0FhG,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CA6D/E"}
1
+ {"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/handoff/pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAkB,WAAW,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAkGhG,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAoB/E"}
@@ -25,6 +25,7 @@
25
25
  import { defaultEstimateTokens, handoffBudget, messageTokens, tokensOf } from './budget.js';
26
26
  import { buildNote, composeNote, elisionMarker, handoffLine, noteTokens } from './note.js';
27
27
  import { segmentTranscript } from './segments.js';
28
+ import { isVolatileTail } from './volatile.js';
28
29
  /** Length of the leading run of `system` messages. */
29
30
  function leadingSystemCount(all) {
30
31
  let n = 0;
@@ -36,13 +37,20 @@ function leadingSystemCount(all) {
36
37
  function noteRole(next) {
37
38
  return next === undefined || next.role === 'assistant' ? 'user' : 'assistant';
38
39
  }
39
- /** Index of the last `user` message, or -1. */
40
+ /** Index of the last `user` message that is a real directive (never a volatile tail), or -1. */
40
41
  function latestDirectiveIndex(convo) {
41
42
  for (let i = convo.length - 1; i >= 0; i--)
42
- if (convo[i].role === 'user')
43
+ if (convo[i].role === 'user' && !isVolatileTail(convo[i]))
43
44
  return i;
44
45
  return -1;
45
46
  }
47
+ /** Where the trailing run of volatile tails begins (`messages.length` when there is none). */
48
+ function trailingVolatileStart(messages) {
49
+ let i = messages.length;
50
+ while (i > 0 && isVolatileTail(messages[i - 1]))
51
+ i -= 1;
52
+ return i;
53
+ }
46
54
  /** Convo indices the caller pinned (pinnable roles only), excluding the directive. */
47
55
  function pinnedIndices(convo, prefixLen, directiveIdx, pinned) {
48
56
  if (!pinned)
@@ -94,8 +102,27 @@ function result(messages, dropped, estimate, extra = {}) {
94
102
  export async function packHandoff(input) {
95
103
  const estimate = input.estimateTokens ?? defaultEstimateTokens;
96
104
  const budget = handoffBudget(input);
97
- const all = input.messages;
98
105
  // Under budget: hand the transcript over untouched.
106
+ if (tokensOf(input.messages, estimate) <= budget)
107
+ return result(input.messages.slice(), 0, estimate);
108
+ // The volatile tail (`volatile.ts`) is set aside, the history packed into what is
109
+ // left, and the tail put back LAST — never the directive, never in the middle. When
110
+ // the history needs the whole budget, the tail is what goes: it is a per-turn aid,
111
+ // the history is the work.
112
+ const cut = trailingVolatileStart(input.messages);
113
+ const volatile = input.messages.slice(cut);
114
+ const volatileTokens = tokensOf(volatile, estimate);
115
+ if (volatile.length > 0) {
116
+ const history = input.messages.slice(0, cut);
117
+ const withTail = await packHistory({ ...input, messages: history }, budget - volatileTokens, estimate);
118
+ if (withTail.fits)
119
+ return result([...withTail.messages, ...volatile], withTail.dropped, estimate, withTail);
120
+ return packHistory({ ...input, messages: history }, budget, estimate);
121
+ }
122
+ return packHistory(input, budget, estimate);
123
+ }
124
+ async function packHistory(input, budget, estimate) {
125
+ const all = input.messages;
99
126
  if (tokensOf(all, estimate) <= budget)
100
127
  return result(all.slice(), 0, estimate);
101
128
  const prefixLen = leadingSystemCount(all);
@@ -1 +1 @@
1
- {"version":3,"file":"pack.js","sourceRoot":"","sources":["../../src/handoff/pack.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pack.js","sourceRoot":"","sources":["../../src/handoff/pack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The per-request VOLATILE tail — everything that changes turn to turn (the run's
3
+ * working-memory brief, the affect block, the budget line, task state) in ONE `user`
4
+ * message appended AFTER the history and opened by {@link VOLATILE_TAIL_TAG}.
5
+ *
6
+ * Two readers depend on that one convention, which is why it lives here and every host
7
+ * builds its tail with {@link volatileTail}:
8
+ *
9
+ * - The gateway's prompt caching places the history breakpoint BEFORE a tagged block,
10
+ * so a tail that changes every turn never becomes the cached prefix. An untagged
11
+ * trailing block is where the breakpoint lands — and then every turn re-bills the
12
+ * whole transcript.
13
+ * - {@link packHandoff} never treats a tagged block as "the latest user directive"
14
+ * and keeps it LAST: an untagged one would be protected in place of the user's real
15
+ * request, which could then be dropped into the summarised middle.
16
+ *
17
+ * A trailing user turn is valid after a tool-result turn on both the OpenAI and the
18
+ * Anthropic shape (Anthropic merges it into the tool_result user turn). It is built per
19
+ * request and never persisted into a transcript.
20
+ */
21
+ import type { HandoffMessage } from './types.js';
22
+ export declare const VOLATILE_TAIL_TAG = "<run-state>";
23
+ /** True when `content` (a string or a content-part array) opens with the tag. */
24
+ export declare function isVolatileContent(content: unknown): boolean;
25
+ /** True for a `user` message that is a volatile tail. */
26
+ export declare function isVolatileTail(message: Pick<HandoffMessage, 'role' | 'content'>): boolean;
27
+ /** The ONE tail message for these sections, or null when every section is empty. */
28
+ export declare function volatileTail(sections: readonly (string | null | undefined)[]): {
29
+ role: 'user';
30
+ content: string;
31
+ } | null;
32
+ //# sourceMappingURL=volatile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volatile.d.ts","sourceRoot":"","sources":["../../src/handoff/volatile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAG/C,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAO3D;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAEzF;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGvH"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The per-request VOLATILE tail — everything that changes turn to turn (the run's
3
+ * working-memory brief, the affect block, the budget line, task state) in ONE `user`
4
+ * message appended AFTER the history and opened by {@link VOLATILE_TAIL_TAG}.
5
+ *
6
+ * Two readers depend on that one convention, which is why it lives here and every host
7
+ * builds its tail with {@link volatileTail}:
8
+ *
9
+ * - The gateway's prompt caching places the history breakpoint BEFORE a tagged block,
10
+ * so a tail that changes every turn never becomes the cached prefix. An untagged
11
+ * trailing block is where the breakpoint lands — and then every turn re-bills the
12
+ * whole transcript.
13
+ * - {@link packHandoff} never treats a tagged block as "the latest user directive"
14
+ * and keeps it LAST: an untagged one would be protected in place of the user's real
15
+ * request, which could then be dropped into the summarised middle.
16
+ *
17
+ * A trailing user turn is valid after a tool-result turn on both the OpenAI and the
18
+ * Anthropic shape (Anthropic merges it into the tool_result user turn). It is built per
19
+ * request and never persisted into a transcript.
20
+ */
21
+ export const VOLATILE_TAIL_TAG = '<run-state>';
22
+ const VOLATILE_TAIL_CLOSE = '</run-state>';
23
+ /** True when `content` (a string or a content-part array) opens with the tag. */
24
+ export function isVolatileContent(content) {
25
+ if (typeof content === 'string')
26
+ return content.startsWith(VOLATILE_TAIL_TAG);
27
+ if (Array.isArray(content)) {
28
+ const first = content[0];
29
+ return typeof first?.text === 'string' && first.text.startsWith(VOLATILE_TAIL_TAG);
30
+ }
31
+ return false;
32
+ }
33
+ /** True for a `user` message that is a volatile tail. */
34
+ export function isVolatileTail(message) {
35
+ return message.role === 'user' && isVolatileContent(message.content);
36
+ }
37
+ /** The ONE tail message for these sections, or null when every section is empty. */
38
+ export function volatileTail(sections) {
39
+ const body = sections.map((s) => (s ?? '').trim()).filter(Boolean).join('\n\n');
40
+ return body ? { role: 'user', content: `${VOLATILE_TAIL_TAG}\n${body}\n${VOLATILE_TAIL_CLOSE}` } : null;
41
+ }
42
+ //# sourceMappingURL=volatile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volatile.js","sourceRoot":"","sources":["../../src/handoff/volatile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAC/C,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAE3C,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC9E,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAmC,CAAC;QAC3D,OAAO,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,cAAc,CAAC,OAAiD;IAC9E,OAAO,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACvE,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,YAAY,CAAC,QAAgD;IAC3E,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,iBAAiB,KAAK,IAAI,KAAK,mBAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Consolidation — what survives a run, as ONE long-term memory per code AREA.
3
+ *
4
+ * A run that spends ninety turns locating the code behind a feature leaves with that
5
+ * knowledge in its transcript and nowhere else, so the next run asked about the same
6
+ * area repeats the whole search. {@link consolidate} turns the run's working memory
7
+ * into a map — the files that mattered, changed first, then reads ranked by how much
8
+ * the run leaned on them — under a key per area (the directory most of them share).
9
+ * Deterministic: built from what the run actually opened, it cannot invent a path.
10
+ *
11
+ * {@link mergeConsolidated} is the WRITE-side rule a keyed store applies, so a small run
12
+ * ADDS to an area's map instead of overwriting the twelve files an earlier one found,
13
+ * and a file this run deleted leaves the map.
14
+ */
15
+ import type { ConsolidateOptions, ConsolidatedMemory, WorkingMemorySnapshot } from './types.js';
16
+ /** Key prefix every consolidated code map carries. */
17
+ export declare const CONSOLIDATED_KEY_PREFIX = "codemap:";
18
+ /** Fewer distinct files than this, with nothing changed, is a lookup — not a map worth keeping. */
19
+ export declare const MIN_CONSOLIDATED_FILES = 3;
20
+ /** The key for an area — stable across runs, so consolidations of one area meet in one memory. */
21
+ export declare function consolidatedKey(area: string): string;
22
+ /**
23
+ * The long-term memory for one finished run, or `null` when the run touched too little
24
+ * to be worth keeping. Files the run deleted are carried as `(deleted)` lines, which
25
+ * {@link mergeConsolidated} applies as removals and never stores.
26
+ */
27
+ export declare function consolidate(snapshot: WorkingMemorySnapshot, opts?: ConsolidateOptions): ConsolidatedMemory | null;
28
+ /**
29
+ * The content to STORE when a consolidated map lands on a key that already holds one:
30
+ * the new run's entries first, then the earlier map's entries it did not touch (an
31
+ * earlier run's `changed` is restated as `changed earlier`, so this run is not credited
32
+ * with edits it never made), minus every file this run deleted, capped. Any other key,
33
+ * or no prior, stores `next` without its `(deleted)` lines.
34
+ *
35
+ * The STORE decides whether `prior` is still live — pass it only when the stored memory
36
+ * has not expired or been superseded, or a retired map comes back to life.
37
+ */
38
+ export declare function mergeConsolidated(key: string, prior: string | null | undefined, next: string): string;
39
+ //# sourceMappingURL=consolidate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidate.d.ts","sourceRoot":"","sources":["../../src/working/consolidate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEhG,sDAAsD;AACtD,eAAO,MAAM,uBAAuB,aAAa,CAAC;AAClD,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAoExC,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,qBAAqB,EAAE,IAAI,GAAE,kBAAuB,GAAG,kBAAkB,GAAG,IAAI,CA6BrH;AAqBD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBrG"}
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Consolidation — what survives a run, as ONE long-term memory per code AREA.
3
+ *
4
+ * A run that spends ninety turns locating the code behind a feature leaves with that
5
+ * knowledge in its transcript and nowhere else, so the next run asked about the same
6
+ * area repeats the whole search. {@link consolidate} turns the run's working memory
7
+ * into a map — the files that mattered, changed first, then reads ranked by how much
8
+ * the run leaned on them — under a key per area (the directory most of them share).
9
+ * Deterministic: built from what the run actually opened, it cannot invent a path.
10
+ *
11
+ * {@link mergeConsolidated} is the WRITE-side rule a keyed store applies, so a small run
12
+ * ADDS to an area's map instead of overwriting the twelve files an earlier one found,
13
+ * and a file this run deleted leaves the map.
14
+ */
15
+ import { rankByCount } from './rank.js';
16
+ /** Key prefix every consolidated code map carries. */
17
+ export const CONSOLIDATED_KEY_PREFIX = 'codemap:';
18
+ /** Fewer distinct files than this, with nothing changed, is a lookup — not a map worth keeping. */
19
+ export const MIN_CONSOLIDATED_FILES = 3;
20
+ const MAX_FILES = 12;
21
+ const MIN_AREA_SEGMENTS = 2;
22
+ const MAX_AREA_SEGMENTS = 4;
23
+ const MAX_TASK_CHARS = 200;
24
+ const MAX_KEY_CHARS = 255;
25
+ /** Dependencies, build output and the knowledge tree itself — never "where the code is". */
26
+ const NOISE_SEGMENTS = new Set(['node_modules', 'dist', '.next', '.turbo', 'coverage', '.git', '.builderforce']);
27
+ const NOISE_FILES = new Set(['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock', 'bun.lockb']);
28
+ const DRIVE = /^[a-z]:\//i;
29
+ /** MSYS / Git-Bash spelling of a drive path: `/c/code/x` ≡ `C:/code/x`. */
30
+ const MSYS_DRIVE = /^\/([a-z])\//i;
31
+ function canonical(raw) {
32
+ let p = raw.trim().replace(/\\/g, '/');
33
+ const msys = MSYS_DRIVE.exec(p);
34
+ if (msys)
35
+ p = `${msys[1]}:/${p.slice(3)}`;
36
+ // Collapse `a//b` and `a/./b`; leading `./` too.
37
+ p = p.replace(/\/{2,}/g, '/').replace(/(^|\/)(\.\/)+/g, '$1');
38
+ return p;
39
+ }
40
+ /**
41
+ * A repo-relative path, or undefined when the path is not a repo file worth mapping:
42
+ * outside the root (or absolute with no root to resolve it against), escaping with
43
+ * `..`, dependencies or build output, or a lockfile. Drive paths compare
44
+ * case-insensitively, as the filesystem does.
45
+ */
46
+ function repoPath(raw, root) {
47
+ let p = canonical(raw);
48
+ if (p.startsWith('/') || DRIVE.test(p)) {
49
+ const base = root ? canonical(root).replace(/\/+$/, '') : '';
50
+ if (!base || base === '/')
51
+ return undefined;
52
+ const under = DRIVE.test(base) ? p.toLowerCase().startsWith(`${base.toLowerCase()}/`) : p.startsWith(`${base}/`);
53
+ if (!under)
54
+ return undefined;
55
+ p = p.slice(base.length + 1);
56
+ }
57
+ const segs = p.split('/');
58
+ if (!p || segs.includes('..'))
59
+ return undefined;
60
+ if (segs.some((s) => NOISE_SEGMENTS.has(s)) || NOISE_FILES.has(segs[segs.length - 1]))
61
+ return undefined;
62
+ return p;
63
+ }
64
+ function dirSegments(file) {
65
+ const parts = file.split('/');
66
+ parts.pop();
67
+ return parts;
68
+ }
69
+ /**
70
+ * The area a set of files belongs to: the DEEPEST directory (to a bounded depth, so
71
+ * keys stay stable from run to run) holding a majority of them, else the depth-2
72
+ * directory holding the most. Root-level files (DONE.md, package.json — touched by
73
+ * many unrelated runs) never decide it.
74
+ */
75
+ function areaOf(files) {
76
+ const placed = files.map(dirSegments).filter((d) => d.length > 0);
77
+ if (placed.length === 0)
78
+ return '(root)';
79
+ const prefixes = (depth) => rankByCount(placed.filter((d) => d.length >= depth).map((d) => d.slice(0, depth).join('/')));
80
+ for (let depth = MAX_AREA_SEGMENTS; depth >= MIN_AREA_SEGMENTS; depth--) {
81
+ const [top] = prefixes(depth);
82
+ if (top && top[1] * 2 > placed.length)
83
+ return top[0];
84
+ }
85
+ return prefixes(MIN_AREA_SEGMENTS)[0]?.[0] ?? prefixes(1)[0][0];
86
+ }
87
+ /** The key for an area — stable across runs, so consolidations of one area meet in one memory. */
88
+ export function consolidatedKey(area) {
89
+ return `${CONSOLIDATED_KEY_PREFIX}${area}`.slice(0, MAX_KEY_CHARS);
90
+ }
91
+ /**
92
+ * The long-term memory for one finished run, or `null` when the run touched too little
93
+ * to be worth keeping. Files the run deleted are carried as `(deleted)` lines, which
94
+ * {@link mergeConsolidated} applies as removals and never stores.
95
+ */
96
+ export function consolidate(snapshot, opts = {}) {
97
+ const keep = (raw) => repoPath(raw, opts.root);
98
+ const kept = (list) => list.map(keep).filter((p) => !!p);
99
+ const deleted = [...new Set(kept(snapshot.deleted))];
100
+ const deletedSet = new Set(deleted);
101
+ const changed = [...new Set(kept([...snapshot.created, ...snapshot.edited]))].filter((p) => !deletedSet.has(p));
102
+ const changedSet = new Set(changed);
103
+ const reads = rankByCount(kept(snapshot.read)).filter(([p]) => !changedSet.has(p) && !deletedSet.has(p));
104
+ const readCounts = new Map(reads);
105
+ const ranked = [...changed, ...reads.map(([p]) => p)];
106
+ if (ranked.length === 0 && deleted.length === 0)
107
+ return null;
108
+ if (changed.length === 0 && deleted.length === 0 && ranked.length < MIN_CONSOLIDATED_FILES)
109
+ return null;
110
+ const shown = ranked.slice(0, MAX_FILES);
111
+ const area = areaOf(ranked.length > 0 ? ranked : deleted);
112
+ const at = (opts.at ?? new Date()).toISOString().slice(0, 10);
113
+ const asked = (snapshot.task ?? '').replace(/\s+/g, ' ').trim().slice(0, MAX_TASK_CHARS);
114
+ const lines = [
115
+ `Code map for \`${area}\` (mapped ${at}${asked ? ` by a run asked: "${asked}"` : ''}).`,
116
+ 'Open these first instead of searching:',
117
+ ...shown.map((p) => {
118
+ if (changedSet.has(p))
119
+ return `- ${p} (changed)`;
120
+ const n = readCounts.get(p) ?? 1;
121
+ return `- ${p}${n > 1 ? ` (read ${n}×)` : ''}`;
122
+ }),
123
+ ...deleted.map((p) => `- ${p} (deleted)`),
124
+ ];
125
+ if (ranked.length > shown.length)
126
+ lines.push(`(+${ranked.length - shown.length} more file(s) touched)`);
127
+ return { key: consolidatedKey(area), content: lines.join('\n') };
128
+ }
129
+ /** `- <path> (<note>)` — the path is everything before the trailing parenthesised note. */
130
+ const ENTRY = /^- (.+?)(?: \(([^()]*)\))?$/;
131
+ const MORE = /^\(\+\d+ more file\(s\) touched\)$/;
132
+ function entriesOf(content) {
133
+ const out = [];
134
+ for (const line of content.split('\n')) {
135
+ const m = ENTRY.exec(line);
136
+ if (m)
137
+ out.push({ path: m[1], note: m[2] });
138
+ }
139
+ return out;
140
+ }
141
+ function render(e) {
142
+ return `- ${e.path}${e.note ? ` (${e.note})` : ''}`;
143
+ }
144
+ /**
145
+ * The content to STORE when a consolidated map lands on a key that already holds one:
146
+ * the new run's entries first, then the earlier map's entries it did not touch (an
147
+ * earlier run's `changed` is restated as `changed earlier`, so this run is not credited
148
+ * with edits it never made), minus every file this run deleted, capped. Any other key,
149
+ * or no prior, stores `next` without its `(deleted)` lines.
150
+ *
151
+ * The STORE decides whether `prior` is still live — pass it only when the stored memory
152
+ * has not expired or been superseded, or a retired map comes back to life.
153
+ */
154
+ export function mergeConsolidated(key, prior, next) {
155
+ if (!key.startsWith(CONSOLIDATED_KEY_PREFIX))
156
+ return next;
157
+ const nextLines = next.split('\n');
158
+ const header = nextLines.filter((l) => !ENTRY.test(l) && !MORE.test(l));
159
+ const fresh = entriesOf(next);
160
+ const removed = new Set(fresh.filter((e) => e.note === 'deleted').map((e) => e.path));
161
+ const seen = new Set(removed);
162
+ const merged = [];
163
+ for (const e of fresh) {
164
+ if (seen.has(e.path))
165
+ continue;
166
+ seen.add(e.path);
167
+ merged.push(render(e));
168
+ }
169
+ for (const e of prior?.trim() ? entriesOf(prior) : []) {
170
+ if (seen.has(e.path) || e.note === 'deleted')
171
+ continue;
172
+ seen.add(e.path);
173
+ merged.push(render(e.note === 'changed' ? { ...e, note: 'changed earlier' } : e));
174
+ }
175
+ const shown = merged.slice(0, MAX_FILES);
176
+ const more = merged.length - shown.length;
177
+ return [...header, ...shown, ...(more > 0 ? [`(+${more} more file(s) touched)`] : [])].join('\n');
178
+ }
179
+ //# sourceMappingURL=consolidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidate.js","sourceRoot":"","sources":["../../src/working/consolidate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Chat consolidation markers — the durable form of a compressed conversation.
3
+ *
4
+ * A long conversation is compressed into ONE summary that becomes the new base context:
5
+ * everything before the marker stays visible in the transcript, but the next run's model
6
+ * seed starts from the marker instead of the full history. The marker is a normal
7
+ * assistant message (so a reader SEES the summary) tagged in its metadata.
8
+ *
9
+ * Two writers:
10
+ * - MANUAL — "Consolidate" / "Fork": the summary covers everything before the marker.
11
+ * - AUTO — a run's working-transcript fold (`transcript.ts`), persisted so the next run
12
+ * (after a reload, on another surface) starts from the note instead of summarizing the
13
+ * whole history again. A fold covers only the OLDER part of the transcript; its
14
+ * `keepFromId` names the first persisted message it did NOT cover, and every message
15
+ * from there on stays verbatim in the seed. Nothing is in neither.
16
+ */
17
+ /** The marker's metadata. `auto` / `keepFromId` / `folded` are set only by a run's fold. */
18
+ export interface ConsolidationMarkerMeta {
19
+ consolidation: true;
20
+ /** Written by auto-compaction, not by a person. */
21
+ auto?: true;
22
+ /** The first persisted message the note does NOT cover (kept verbatim after the marker). */
23
+ keepFromId?: number;
24
+ /** How many transcript messages the fold newly compressed. */
25
+ folded?: number;
26
+ }
27
+ /** The metadata of a manual marker. */
28
+ export declare const CONSOLIDATION_META: ConsolidationMarkerMeta;
29
+ /** Serialized metadata for a marker message (ready to persist). Manual when no `auto`. */
30
+ export declare function consolidationMetadata(auto?: {
31
+ keepFromId?: number;
32
+ folded?: number;
33
+ }): string;
34
+ /** The marker metadata a persisted message carries, or null when it is not a marker. */
35
+ export declare function consolidationMarkerOf(msg: {
36
+ metadata?: string | null;
37
+ }): ConsolidationMarkerMeta | null;
38
+ /** True when a persisted message is a consolidation marker (by its metadata flag). */
39
+ export declare function isConsolidationMarker(msg: {
40
+ metadata?: string | null;
41
+ }): boolean;
42
+ /** The index of the LAST consolidation marker in a message list, or -1 if none. */
43
+ export declare function lastConsolidationIndex(messages: ReadonlyArray<{
44
+ metadata?: string | null;
45
+ }>): number;
46
+ /**
47
+ * Trim a message list to the compressed context: the last marker, then what it does not
48
+ * cover. A manual marker covers everything before it (the list from the marker on). An
49
+ * auto marker covers up to its `keepFromId`: the marker, then every message from that id
50
+ * on (other markers dropped — an older note is superseded by the newer one). Unchanged
51
+ * when there is no marker; a `keepFromId` no longer in the list reads as manual.
52
+ */
53
+ export declare function scopeToConsolidation<T extends {
54
+ id?: number;
55
+ metadata?: string | null;
56
+ }>(messages: T[]): T[];
57
+ /**
58
+ * Where an auto marker's verbatim part begins: given the persisted messages the run's
59
+ * transcript holds (`anchors`: transcript index → message id) and the index the fold now
60
+ * covers up to (exclusive), the id of the persisted message the next seed must keep from.
61
+ *
62
+ * Exact when a persisted message sits AT `coveredEnd` (the fold ended inside seeded
63
+ * history). Otherwise the nearest persisted message BEFORE it — conservative: the span
64
+ * between it and `coveredEnd` is then both in the note and verbatim, never in neither.
65
+ * Undefined when no persisted message precedes the cut (nothing to keep from).
66
+ */
67
+ export declare function foldKeepFromId(anchors: ReadonlyArray<{
68
+ index: number;
69
+ id: number;
70
+ }>, coveredEnd: number): number | undefined;
71
+ /** The visible header prefixed onto a consolidation summary so a reader recognizes it. */
72
+ export declare const CONSOLIDATION_MARKER_PREFIX = "\uD83D\uDCCC **Consolidated summary** \u2014 context continues from here.\n\n";
73
+ /** Wrap a raw summary as the marker's visible content (prefix + summary). */
74
+ export declare function consolidationMarkerContent(summary: string): string;
75
+ //# sourceMappingURL=consolidationMarker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidationMarker.d.ts","sourceRoot":"","sources":["../../src/working/consolidationMarker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,4FAA4F;AAC5F,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,IAAI,CAAC;IACpB,mDAAmD;IACnD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uCAAuC;AACvC,eAAO,MAAM,kBAAkB,EAAE,uBAAiD,CAAC;AAEnF,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAS7F;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,uBAAuB,GAAG,IAAI,CAcvG;AAED,sFAAsF;AACtF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,OAAO,CAEhF;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,GAAG,MAAM,CAKpG;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAQ5G;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM5H;AAED,0FAA0F;AAC1F,eAAO,MAAM,2BAA2B,kFAAmE,CAAC;AAE5G,6EAA6E;AAC7E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Chat consolidation markers — the durable form of a compressed conversation.
3
+ *
4
+ * A long conversation is compressed into ONE summary that becomes the new base context:
5
+ * everything before the marker stays visible in the transcript, but the next run's model
6
+ * seed starts from the marker instead of the full history. The marker is a normal
7
+ * assistant message (so a reader SEES the summary) tagged in its metadata.
8
+ *
9
+ * Two writers:
10
+ * - MANUAL — "Consolidate" / "Fork": the summary covers everything before the marker.
11
+ * - AUTO — a run's working-transcript fold (`transcript.ts`), persisted so the next run
12
+ * (after a reload, on another surface) starts from the note instead of summarizing the
13
+ * whole history again. A fold covers only the OLDER part of the transcript; its
14
+ * `keepFromId` names the first persisted message it did NOT cover, and every message
15
+ * from there on stays verbatim in the seed. Nothing is in neither.
16
+ */
17
+ /** The metadata of a manual marker. */
18
+ export const CONSOLIDATION_META = { consolidation: true };
19
+ /** Serialized metadata for a marker message (ready to persist). Manual when no `auto`. */
20
+ export function consolidationMetadata(auto) {
21
+ if (!auto)
22
+ return JSON.stringify(CONSOLIDATION_META);
23
+ const meta = {
24
+ consolidation: true,
25
+ auto: true,
26
+ ...(auto.keepFromId !== undefined ? { keepFromId: auto.keepFromId } : {}),
27
+ ...(auto.folded !== undefined ? { folded: auto.folded } : {}),
28
+ };
29
+ return JSON.stringify(meta);
30
+ }
31
+ /** The marker metadata a persisted message carries, or null when it is not a marker. */
32
+ export function consolidationMarkerOf(msg) {
33
+ if (!msg.metadata)
34
+ return null;
35
+ try {
36
+ const m = JSON.parse(msg.metadata);
37
+ if (m?.consolidation !== true)
38
+ return null;
39
+ return {
40
+ consolidation: true,
41
+ ...(m.auto === true ? { auto: true } : {}),
42
+ ...(typeof m.keepFromId === 'number' && Number.isFinite(m.keepFromId) ? { keepFromId: m.keepFromId } : {}),
43
+ ...(typeof m.folded === 'number' && Number.isFinite(m.folded) && m.folded > 0 ? { folded: m.folded } : {}),
44
+ };
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
50
+ /** True when a persisted message is a consolidation marker (by its metadata flag). */
51
+ export function isConsolidationMarker(msg) {
52
+ return consolidationMarkerOf(msg) !== null;
53
+ }
54
+ /** The index of the LAST consolidation marker in a message list, or -1 if none. */
55
+ export function lastConsolidationIndex(messages) {
56
+ for (let i = messages.length - 1; i >= 0; i--) {
57
+ if (isConsolidationMarker(messages[i]))
58
+ return i;
59
+ }
60
+ return -1;
61
+ }
62
+ /**
63
+ * Trim a message list to the compressed context: the last marker, then what it does not
64
+ * cover. A manual marker covers everything before it (the list from the marker on). An
65
+ * auto marker covers up to its `keepFromId`: the marker, then every message from that id
66
+ * on (other markers dropped — an older note is superseded by the newer one). Unchanged
67
+ * when there is no marker; a `keepFromId` no longer in the list reads as manual.
68
+ */
69
+ export function scopeToConsolidation(messages) {
70
+ const idx = lastConsolidationIndex(messages);
71
+ if (idx < 0)
72
+ return messages;
73
+ const marker = messages[idx];
74
+ const keepFromId = consolidationMarkerOf(marker)?.keepFromId;
75
+ const from = keepFromId === undefined ? -1 : messages.findIndex((m) => m.id === keepFromId);
76
+ if (from < 0 || from > idx)
77
+ return messages.slice(idx);
78
+ return [marker, ...messages.slice(from).filter((m) => m !== marker && !isConsolidationMarker(m))];
79
+ }
80
+ /**
81
+ * Where an auto marker's verbatim part begins: given the persisted messages the run's
82
+ * transcript holds (`anchors`: transcript index → message id) and the index the fold now
83
+ * covers up to (exclusive), the id of the persisted message the next seed must keep from.
84
+ *
85
+ * Exact when a persisted message sits AT `coveredEnd` (the fold ended inside seeded
86
+ * history). Otherwise the nearest persisted message BEFORE it — conservative: the span
87
+ * between it and `coveredEnd` is then both in the note and verbatim, never in neither.
88
+ * Undefined when no persisted message precedes the cut (nothing to keep from).
89
+ */
90
+ export function foldKeepFromId(anchors, coveredEnd) {
91
+ let best;
92
+ for (const a of anchors) {
93
+ if (a.index <= coveredEnd && (!best || a.index > best.index))
94
+ best = a;
95
+ }
96
+ return best?.id;
97
+ }
98
+ /** The visible header prefixed onto a consolidation summary so a reader recognizes it. */
99
+ export const CONSOLIDATION_MARKER_PREFIX = '📌 **Consolidated summary** — context continues from here.\n\n';
100
+ /** Wrap a raw summary as the marker's visible content (prefix + summary). */
101
+ export function consolidationMarkerContent(summary) {
102
+ return `${CONSOLIDATION_MARKER_PREFIX}${summary.trim()}`;
103
+ }
104
+ //# sourceMappingURL=consolidationMarker.js.map