trellis-hgl-core 0.6.0-beta.18

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 (202) hide show
  1. package/LICENSE +235 -0
  2. package/dist/channel/api/assert.d.ts +3 -0
  3. package/dist/channel/api/assert.d.ts.map +1 -0
  4. package/dist/channel/api/assert.js +11 -0
  5. package/dist/channel/api/assert.js.map +1 -0
  6. package/dist/channel/api/context.d.ts +21 -0
  7. package/dist/channel/api/context.d.ts.map +1 -0
  8. package/dist/channel/api/context.js +99 -0
  9. package/dist/channel/api/context.js.map +1 -0
  10. package/dist/channel/api/create.d.ts +9 -0
  11. package/dist/channel/api/create.d.ts.map +1 -0
  12. package/dist/channel/api/create.js +104 -0
  13. package/dist/channel/api/create.js.map +1 -0
  14. package/dist/channel/api/inbox.d.ts +51 -0
  15. package/dist/channel/api/inbox.d.ts.map +1 -0
  16. package/dist/channel/api/inbox.js +176 -0
  17. package/dist/channel/api/inbox.js.map +1 -0
  18. package/dist/channel/api/interrupt.d.ts +31 -0
  19. package/dist/channel/api/interrupt.d.ts.map +1 -0
  20. package/dist/channel/api/interrupt.js +102 -0
  21. package/dist/channel/api/interrupt.js.map +1 -0
  22. package/dist/channel/api/post-thread.d.ts +14 -0
  23. package/dist/channel/api/post-thread.d.ts.map +1 -0
  24. package/dist/channel/api/post-thread.js +106 -0
  25. package/dist/channel/api/post-thread.js.map +1 -0
  26. package/dist/channel/api/read.d.ts +17 -0
  27. package/dist/channel/api/read.d.ts.map +1 -0
  28. package/dist/channel/api/read.js +44 -0
  29. package/dist/channel/api/read.js.map +1 -0
  30. package/dist/channel/api/resolve.d.ts +21 -0
  31. package/dist/channel/api/resolve.d.ts.map +1 -0
  32. package/dist/channel/api/resolve.js +28 -0
  33. package/dist/channel/api/resolve.js.map +1 -0
  34. package/dist/channel/api/runtime.d.ts +70 -0
  35. package/dist/channel/api/runtime.d.ts.map +1 -0
  36. package/dist/channel/api/runtime.js +11 -0
  37. package/dist/channel/api/runtime.js.map +1 -0
  38. package/dist/channel/api/send.d.ts +4 -0
  39. package/dist/channel/api/send.d.ts.map +1 -0
  40. package/dist/channel/api/send.js +44 -0
  41. package/dist/channel/api/send.js.map +1 -0
  42. package/dist/channel/api/spawn.d.ts +13 -0
  43. package/dist/channel/api/spawn.d.ts.map +1 -0
  44. package/dist/channel/api/spawn.js +54 -0
  45. package/dist/channel/api/spawn.js.map +1 -0
  46. package/dist/channel/api/title.d.ts +5 -0
  47. package/dist/channel/api/title.d.ts.map +1 -0
  48. package/dist/channel/api/title.js +40 -0
  49. package/dist/channel/api/title.js.map +1 -0
  50. package/dist/channel/api/types.d.ts +64 -0
  51. package/dist/channel/api/types.d.ts.map +1 -0
  52. package/dist/channel/api/types.js +2 -0
  53. package/dist/channel/api/types.js.map +1 -0
  54. package/dist/channel/api/watch-channels.d.ts +40 -0
  55. package/dist/channel/api/watch-channels.d.ts.map +1 -0
  56. package/dist/channel/api/watch-channels.js +143 -0
  57. package/dist/channel/api/watch-channels.js.map +1 -0
  58. package/dist/channel/api/watch.d.ts +11 -0
  59. package/dist/channel/api/watch.d.ts.map +1 -0
  60. package/dist/channel/api/watch.js +17 -0
  61. package/dist/channel/api/watch.js.map +1 -0
  62. package/dist/channel/api/workers.d.ts +69 -0
  63. package/dist/channel/api/workers.d.ts.map +1 -0
  64. package/dist/channel/api/workers.js +145 -0
  65. package/dist/channel/api/workers.js.map +1 -0
  66. package/dist/channel/index.d.ts +38 -0
  67. package/dist/channel/index.d.ts.map +1 -0
  68. package/dist/channel/index.js +23 -0
  69. package/dist/channel/index.js.map +1 -0
  70. package/dist/channel/internal/store/channel-metadata.d.ts +23 -0
  71. package/dist/channel/internal/store/channel-metadata.d.ts.map +1 -0
  72. package/dist/channel/internal/store/channel-metadata.js +94 -0
  73. package/dist/channel/internal/store/channel-metadata.js.map +1 -0
  74. package/dist/channel/internal/store/delivery.d.ts +27 -0
  75. package/dist/channel/internal/store/delivery.d.ts.map +1 -0
  76. package/dist/channel/internal/store/delivery.js +37 -0
  77. package/dist/channel/internal/store/delivery.js.map +1 -0
  78. package/dist/channel/internal/store/events.d.ts +203 -0
  79. package/dist/channel/internal/store/events.d.ts.map +1 -0
  80. package/dist/channel/internal/store/events.js +185 -0
  81. package/dist/channel/internal/store/events.js.map +1 -0
  82. package/dist/channel/internal/store/filter.d.ts +22 -0
  83. package/dist/channel/internal/store/filter.d.ts.map +1 -0
  84. package/dist/channel/internal/store/filter.js +78 -0
  85. package/dist/channel/internal/store/filter.js.map +1 -0
  86. package/dist/channel/internal/store/inbox.d.ts +17 -0
  87. package/dist/channel/internal/store/inbox.d.ts.map +1 -0
  88. package/dist/channel/internal/store/inbox.js +30 -0
  89. package/dist/channel/internal/store/inbox.js.map +1 -0
  90. package/dist/channel/internal/store/lock.d.ts +17 -0
  91. package/dist/channel/internal/store/lock.d.ts.map +1 -0
  92. package/dist/channel/internal/store/lock.js +88 -0
  93. package/dist/channel/internal/store/lock.js.map +1 -0
  94. package/dist/channel/internal/store/paths.d.ts +43 -0
  95. package/dist/channel/internal/store/paths.d.ts.map +1 -0
  96. package/dist/channel/internal/store/paths.js +233 -0
  97. package/dist/channel/internal/store/paths.js.map +1 -0
  98. package/dist/channel/internal/store/schema.d.ts +77 -0
  99. package/dist/channel/internal/store/schema.d.ts.map +1 -0
  100. package/dist/channel/internal/store/schema.js +127 -0
  101. package/dist/channel/internal/store/schema.js.map +1 -0
  102. package/dist/channel/internal/store/seq.d.ts +12 -0
  103. package/dist/channel/internal/store/seq.d.ts.map +1 -0
  104. package/dist/channel/internal/store/seq.js +133 -0
  105. package/dist/channel/internal/store/seq.js.map +1 -0
  106. package/dist/channel/internal/store/thread-state.d.ts +37 -0
  107. package/dist/channel/internal/store/thread-state.d.ts.map +1 -0
  108. package/dist/channel/internal/store/thread-state.js +206 -0
  109. package/dist/channel/internal/store/thread-state.js.map +1 -0
  110. package/dist/channel/internal/store/watch.d.ts +10 -0
  111. package/dist/channel/internal/store/watch.d.ts.map +1 -0
  112. package/dist/channel/internal/store/watch.js +122 -0
  113. package/dist/channel/internal/store/watch.js.map +1 -0
  114. package/dist/channel/internal/store/worker-state.d.ts +49 -0
  115. package/dist/channel/internal/store/worker-state.d.ts.map +1 -0
  116. package/dist/channel/internal/store/worker-state.js +207 -0
  117. package/dist/channel/internal/store/worker-state.js.map +1 -0
  118. package/dist/index.d.ts +3 -0
  119. package/dist/index.d.ts.map +1 -0
  120. package/dist/index.js +7 -0
  121. package/dist/index.js.map +1 -0
  122. package/dist/mem/adapters/claude.d.ts +22 -0
  123. package/dist/mem/adapters/claude.d.ts.map +1 -0
  124. package/dist/mem/adapters/claude.js +252 -0
  125. package/dist/mem/adapters/claude.js.map +1 -0
  126. package/dist/mem/adapters/codex.d.ts +35 -0
  127. package/dist/mem/adapters/codex.d.ts.map +1 -0
  128. package/dist/mem/adapters/codex.js +222 -0
  129. package/dist/mem/adapters/codex.js.map +1 -0
  130. package/dist/mem/adapters/opencode.d.ts +19 -0
  131. package/dist/mem/adapters/opencode.d.ts.map +1 -0
  132. package/dist/mem/adapters/opencode.js +25 -0
  133. package/dist/mem/adapters/opencode.js.map +1 -0
  134. package/dist/mem/context.d.ts +23 -0
  135. package/dist/mem/context.d.ts.map +1 -0
  136. package/dist/mem/context.js +118 -0
  137. package/dist/mem/context.js.map +1 -0
  138. package/dist/mem/dialogue.d.ts +17 -0
  139. package/dist/mem/dialogue.d.ts.map +1 -0
  140. package/dist/mem/dialogue.js +51 -0
  141. package/dist/mem/dialogue.js.map +1 -0
  142. package/dist/mem/filter.d.ts +31 -0
  143. package/dist/mem/filter.d.ts.map +1 -0
  144. package/dist/mem/filter.js +70 -0
  145. package/dist/mem/filter.js.map +1 -0
  146. package/dist/mem/index.d.ts +18 -0
  147. package/dist/mem/index.d.ts.map +1 -0
  148. package/dist/mem/index.js +17 -0
  149. package/dist/mem/index.js.map +1 -0
  150. package/dist/mem/internal/jsonl.d.ts +35 -0
  151. package/dist/mem/internal/jsonl.d.ts.map +1 -0
  152. package/dist/mem/internal/jsonl.js +125 -0
  153. package/dist/mem/internal/jsonl.js.map +1 -0
  154. package/dist/mem/internal/paths.d.ts +18 -0
  155. package/dist/mem/internal/paths.d.ts.map +1 -0
  156. package/dist/mem/internal/paths.js +51 -0
  157. package/dist/mem/internal/paths.js.map +1 -0
  158. package/dist/mem/phase.d.ts +45 -0
  159. package/dist/mem/phase.d.ts.map +1 -0
  160. package/dist/mem/phase.js +220 -0
  161. package/dist/mem/phase.js.map +1 -0
  162. package/dist/mem/projects.d.ts +13 -0
  163. package/dist/mem/projects.d.ts.map +1 -0
  164. package/dist/mem/projects.js +37 -0
  165. package/dist/mem/projects.js.map +1 -0
  166. package/dist/mem/search.d.ts +32 -0
  167. package/dist/mem/search.d.ts.map +1 -0
  168. package/dist/mem/search.js +125 -0
  169. package/dist/mem/search.js.map +1 -0
  170. package/dist/mem/sessions.d.ts +37 -0
  171. package/dist/mem/sessions.d.ts.map +1 -0
  172. package/dist/mem/sessions.js +270 -0
  173. package/dist/mem/sessions.js.map +1 -0
  174. package/dist/mem/types.d.ts +176 -0
  175. package/dist/mem/types.d.ts.map +1 -0
  176. package/dist/mem/types.js +10 -0
  177. package/dist/mem/types.js.map +1 -0
  178. package/dist/task/index.d.ts +9 -0
  179. package/dist/task/index.d.ts.map +1 -0
  180. package/dist/task/index.js +9 -0
  181. package/dist/task/index.js.map +1 -0
  182. package/dist/task/paths.d.ts +37 -0
  183. package/dist/task/paths.d.ts.map +1 -0
  184. package/dist/task/paths.js +49 -0
  185. package/dist/task/paths.js.map +1 -0
  186. package/dist/task/phase.d.ts +27 -0
  187. package/dist/task/phase.d.ts.map +1 -0
  188. package/dist/task/phase.js +24 -0
  189. package/dist/task/phase.js.map +1 -0
  190. package/dist/task/records.d.ts +39 -0
  191. package/dist/task/records.d.ts.map +1 -0
  192. package/dist/task/records.js +89 -0
  193. package/dist/task/records.js.map +1 -0
  194. package/dist/task/schema.d.ts +77 -0
  195. package/dist/task/schema.d.ts.map +1 -0
  196. package/dist/task/schema.js +220 -0
  197. package/dist/task/schema.js.map +1 -0
  198. package/dist/testing/index.d.ts +2 -0
  199. package/dist/testing/index.d.ts.map +1 -0
  200. package/dist/testing/index.js +4 -0
  201. package/dist/testing/index.js.map +1 -0
  202. package/package.json +78 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mem/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,YAAY,EACV,aAAa,EACb,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,cAAc,EACd,aAAa,EACb,SAAS,EACT,UAAU,EACV,cAAc,EACd,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Public surface for `@mindfoldhq/trellis-core/mem` — reusable retrieval and
3
+ * dialogue-context extraction over persisted Claude Code / Codex / OpenCode
4
+ * sessions.
5
+ *
6
+ * This subpackage is intentionally NOT re-exported from the root
7
+ * `@mindfoldhq/trellis-core` barrel. Import it explicitly:
8
+ *
9
+ * import { searchMemSessions } from "@mindfoldhq/trellis-core/mem";
10
+ *
11
+ * v1 scope: persisted-session search and context extraction only. It does not
12
+ * read channel / forum / thread event logs and has no cursor / pagination.
13
+ */
14
+ export { listMemSessions, searchMemSessions, extractMemDialogue, MemSessionNotFoundError, } from "./sessions.js";
15
+ export { readMemContext } from "./context.js";
16
+ export { listMemProjects } from "./projects.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mem/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Streaming JSONL / JSON readers for the persisted-session adapters.
3
+ *
4
+ * Zero-dependency on purpose — `@mindfoldhq/trellis-core` does not depend on
5
+ * `zod`. The original CLI implementation validated every line against a Zod
6
+ * schema; the external session formats were all declared `.loose()` with every
7
+ * field `.optional()`, so the only thing the schema actually rejected was a
8
+ * top-level non-object line — which the `0x7b` byte-prefix fast-reject already
9
+ * filters. Adapters therefore receive each parsed line cast to a hand-written
10
+ * loose interface and read fields defensively.
11
+ */
12
+ /**
13
+ * Walk a JSONL file line-by-line, invoking `onLine` with each parsed object.
14
+ * Bad JSON lines are skipped. Returning the literal `"stop"` from `onLine`
15
+ * halts iteration.
16
+ *
17
+ * Chunked sync streaming: 256 KB read window, leftover preserved across chunks
18
+ * for split-line reassembly — bounded heap on multi-MB session files and a
19
+ * `"stop"` short-circuit that avoids reading the whole file when only the head
20
+ * is needed.
21
+ *
22
+ * Byte-prefix fast-reject: a JSONL event line virtually always begins with `{`.
23
+ * Lines whose first byte is not `{` are blanks / log preambles / partial writes
24
+ * and are skipped before paying the `JSON.parse` cost.
25
+ */
26
+ export declare function readJsonl<T>(file: string, onLine: (obj: T) => unknown): void;
27
+ /** Read just the first parseable JSONL object (stops after one line). */
28
+ export declare function readJsonlFirst<T>(file: string): T | undefined;
29
+ /** Find the first JSONL object satisfying `predicate`, scanning at most
30
+ * `maxLines` lines. */
31
+ export declare function findInJsonl<T>(file: string, predicate: (obj: T) => boolean, maxLines?: number): T | undefined;
32
+ /** Read and JSON-parse a whole file; returns `undefined` on read / parse
33
+ * failure. The caller is responsible for shape-checking the result. */
34
+ export declare function readJsonFile<T>(file: string): T | undefined;
35
+ //# sourceMappingURL=jsonl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../../src/mem/internal/jsonl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,GAAG,IAAI,CAqD5E;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAO7D;AAED;uBACuB;AACvB,wBAAgB,WAAW,CAAC,CAAC,EAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,EAC9B,QAAQ,SAAM,GACb,CAAC,GAAG,SAAS,CAYf;AAED;uEACuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAM3D"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Streaming JSONL / JSON readers for the persisted-session adapters.
3
+ *
4
+ * Zero-dependency on purpose — `@mindfoldhq/trellis-core` does not depend on
5
+ * `zod`. The original CLI implementation validated every line against a Zod
6
+ * schema; the external session formats were all declared `.loose()` with every
7
+ * field `.optional()`, so the only thing the schema actually rejected was a
8
+ * top-level non-object line — which the `0x7b` byte-prefix fast-reject already
9
+ * filters. Adapters therefore receive each parsed line cast to a hand-written
10
+ * loose interface and read fields defensively.
11
+ */
12
+ import * as fs from "node:fs";
13
+ const CHUNK = 256 * 1024;
14
+ const OPEN_BRACE = 0x7b; // '{'
15
+ /**
16
+ * Walk a JSONL file line-by-line, invoking `onLine` with each parsed object.
17
+ * Bad JSON lines are skipped. Returning the literal `"stop"` from `onLine`
18
+ * halts iteration.
19
+ *
20
+ * Chunked sync streaming: 256 KB read window, leftover preserved across chunks
21
+ * for split-line reassembly — bounded heap on multi-MB session files and a
22
+ * `"stop"` short-circuit that avoids reading the whole file when only the head
23
+ * is needed.
24
+ *
25
+ * Byte-prefix fast-reject: a JSONL event line virtually always begins with `{`.
26
+ * Lines whose first byte is not `{` are blanks / log preambles / partial writes
27
+ * and are skipped before paying the `JSON.parse` cost.
28
+ */
29
+ export function readJsonl(file, onLine) {
30
+ let fd;
31
+ try {
32
+ fd = fs.openSync(file, "r");
33
+ }
34
+ catch {
35
+ return;
36
+ }
37
+ const buf = Buffer.alloc(CHUNK);
38
+ let leftover = "";
39
+ try {
40
+ let stop = false;
41
+ while (!stop) {
42
+ const n = fs.readSync(fd, buf, 0, CHUNK, null);
43
+ if (n === 0)
44
+ break;
45
+ const chunk = leftover + buf.toString("utf8", 0, n);
46
+ let from = 0;
47
+ while (true) {
48
+ const nl = chunk.indexOf("\n", from);
49
+ if (nl === -1) {
50
+ leftover = chunk.slice(from);
51
+ break;
52
+ }
53
+ const line = chunk.slice(from, nl);
54
+ from = nl + 1;
55
+ if (!line)
56
+ continue;
57
+ if (line.charCodeAt(0) !== OPEN_BRACE)
58
+ continue;
59
+ let raw;
60
+ try {
61
+ raw = JSON.parse(line);
62
+ }
63
+ catch {
64
+ continue;
65
+ }
66
+ if (onLine(raw) === "stop") {
67
+ stop = true;
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ if (!stop && leftover) {
73
+ // File ended without a trailing newline — process the last partial line.
74
+ const line = leftover;
75
+ if (line.charCodeAt(0) === OPEN_BRACE) {
76
+ try {
77
+ const raw = JSON.parse(line);
78
+ onLine(raw);
79
+ }
80
+ catch {
81
+ /* skip */
82
+ }
83
+ }
84
+ }
85
+ }
86
+ finally {
87
+ fs.closeSync(fd);
88
+ }
89
+ }
90
+ /** Read just the first parseable JSONL object (stops after one line). */
91
+ export function readJsonlFirst(file) {
92
+ let result;
93
+ readJsonl(file, (obj) => {
94
+ result = obj;
95
+ return "stop";
96
+ });
97
+ return result;
98
+ }
99
+ /** Find the first JSONL object satisfying `predicate`, scanning at most
100
+ * `maxLines` lines. */
101
+ export function findInJsonl(file, predicate, maxLines = 200) {
102
+ let count = 0;
103
+ let hit;
104
+ readJsonl(file, (obj) => {
105
+ count++;
106
+ if (predicate(obj)) {
107
+ hit = obj;
108
+ return "stop";
109
+ }
110
+ if (count >= maxLines)
111
+ return "stop";
112
+ });
113
+ return hit;
114
+ }
115
+ /** Read and JSON-parse a whole file; returns `undefined` on read / parse
116
+ * failure. The caller is responsible for shape-checking the result. */
117
+ export function readJsonFile(file) {
118
+ try {
119
+ return JSON.parse(fs.readFileSync(file, "utf8"));
120
+ }
121
+ catch {
122
+ return undefined;
123
+ }
124
+ }
125
+ //# sourceMappingURL=jsonl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../../src/mem/internal/jsonl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Default home-based session roots for the persisted-session adapters.
3
+ *
4
+ * `HOME` is captured once at module load — consumers that need to point the
5
+ * adapters at a fake home (tests) must mock `node:os` before importing any
6
+ * mem module.
7
+ */
8
+ export declare const HOME: string;
9
+ export declare const CLAUDE_PROJECTS: string;
10
+ export declare const CODEX_SESSIONS: string;
11
+ /** Claude sanitizes a cwd into its on-disk project dir name by replacing
12
+ * path separators plus `_` with `-`. On Windows the drive separator `:` is
13
+ * also flattened so the result stays a single valid directory name. */
14
+ export declare function claudeProjectDirFromCwd(cwd: string): string;
15
+ /** Lazy stack-based recursive file walk — yields every file path under
16
+ * `root`. Missing roots and unreadable directories are skipped silently. */
17
+ export declare function walkDir(root: string): Generator<string>;
18
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/mem/internal/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,eAAO,MAAM,IAAI,QAAe,CAAC;AACjC,eAAO,MAAM,eAAe,QAAyC,CAAC;AACtE,eAAO,MAAM,cAAc,QAAwC,CAAC;AAEpE;;uEAEuE;AACvE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3D;AAQD;4EAC4E;AAC5E,wBAAiB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAkBxD"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Default home-based session roots for the persisted-session adapters.
3
+ *
4
+ * `HOME` is captured once at module load — consumers that need to point the
5
+ * adapters at a fake home (tests) must mock `node:os` before importing any
6
+ * mem module.
7
+ */
8
+ import * as fs from "node:fs";
9
+ import * as os from "node:os";
10
+ import * as path from "node:path";
11
+ export const HOME = os.homedir();
12
+ export const CLAUDE_PROJECTS = path.join(HOME, ".claude", "projects");
13
+ export const CODEX_SESSIONS = path.join(HOME, ".codex", "sessions");
14
+ /** Claude sanitizes a cwd into its on-disk project dir name by replacing
15
+ * path separators plus `_` with `-`. On Windows the drive separator `:` is
16
+ * also flattened so the result stays a single valid directory name. */
17
+ export function claudeProjectDirFromCwd(cwd) {
18
+ return path.join(CLAUDE_PROJECTS, sanitizeClaudeProjectCwd(cwd));
19
+ }
20
+ function sanitizeClaudeProjectCwd(cwd) {
21
+ return process.platform === "win32"
22
+ ? cwd.replace(/[\\/:_]/g, "-")
23
+ : cwd.replace(/[/_]/g, "-");
24
+ }
25
+ /** Lazy stack-based recursive file walk — yields every file path under
26
+ * `root`. Missing roots and unreadable directories are skipped silently. */
27
+ export function* walkDir(root) {
28
+ if (!fs.existsSync(root))
29
+ return;
30
+ const stack = [root];
31
+ while (stack.length) {
32
+ const cur = stack.pop();
33
+ if (cur === undefined)
34
+ break;
35
+ let entries;
36
+ try {
37
+ entries = fs.readdirSync(cur, { withFileTypes: true });
38
+ }
39
+ catch {
40
+ continue;
41
+ }
42
+ for (const e of entries) {
43
+ const p = path.join(cur, e.name);
44
+ if (e.isDirectory())
45
+ stack.push(p);
46
+ else if (e.isFile())
47
+ yield p;
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/mem/internal/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AAEpE;;uEAEuE;AACvE,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,wBAAwB,CAAC,GAAW;IAC3C,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO;QACjC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;QAC9B,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC;AAED;4EAC4E;AAC5E,MAAM,SAAS,CAAC,CAAC,OAAO,CAAC,IAAY;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IACjC,MAAM,KAAK,GAAa,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM;QAC7B,IAAI,OAAoB,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBAC9B,IAAI,CAAC,CAAC,MAAM,EAAE;gBAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `task.py` command parsing and brainstorm-window slicing.
3
+ *
4
+ * Pure logic only — boundary signals are recovered from raw shell-call strings;
5
+ * the per-platform raw-JSONL pass that produces those strings lives in the
6
+ * adapters.
7
+ */
8
+ import type { BrainstormWindow, ParsedTaskPyCommand, TaskPyEvent } from "./types.js";
9
+ /**
10
+ * Find ALL `task.py create|start` invocations in a single Bash command string.
11
+ * A real Bash invocation can contain several (e.g.
12
+ * `SMOKE=$(task.py create …); task.py start "$SMOKE"`). Returned in source
13
+ * order; each entry's args are bounded to the next `task.py` invocation or
14
+ * end-of-line.
15
+ *
16
+ * False-positive guard: `task.py` must appear at the start of the command,
17
+ * after whitespace, or after a path separator — never embedded inside a flag
18
+ * value like `--slug=task.py-create-foo`.
19
+ */
20
+ export declare function parseTaskPyCommandsAll(cmd: string): ParsedTaskPyCommand[];
21
+ /** Single-result wrapper — returns the first occurrence, or `null` if none. */
22
+ export declare function parseTaskPyCommand(cmd: string): ParsedTaskPyCommand | null;
23
+ /** Best-effort shell-arg splitter: respects `"…"` / `'…'` quoting, splits on
24
+ * whitespace, treats `;`, `|`, `&`, `(`, `)` as token boundaries, and strips
25
+ * trailing shell-meta cruft (`)};&|>`) from each token. Not a full POSIX
26
+ * parser — sufficient for pulling slugs / paths out of `task.py` invocations. */
27
+ export declare function splitShellArgs(s: string): string[];
28
+ /** Derive a slug from a `start` task-dir path like
29
+ * `.trellis/tasks/05-08-mem-phase-slice/` → `mem-phase-slice` (the `MM-DD-`
30
+ * date prefix is stripped so it matches a `--slug` on the paired `create`). */
31
+ export declare function slugFromTaskDir(p: string | undefined): string | undefined;
32
+ /**
33
+ * Pair `create` → `start` events into brainstorm windows.
34
+ *
35
+ * Pairing strategy:
36
+ * 1. Slug match wins regardless of position.
37
+ * 2. FIFO fallback: remaining creates pair with the next unmatched start
38
+ * appearing after them in event order.
39
+ * 3. Unmatched create → `[create, totalTurns)`.
40
+ * 4. Unmatched start → `[0, start)`.
41
+ *
42
+ * Windows are sorted by `startTurn` ascending for stable output ordering.
43
+ */
44
+ export declare function buildBrainstormWindows(events: readonly TaskPyEvent[], totalTurns: number): BrainstormWindow[];
45
+ //# sourceMappingURL=phase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase.d.ts","sourceRoot":"","sources":["../../src/mem/phase.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAgCzE;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAG1E;AAqCD;;;iFAGiF;AACjF,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAmClD;AAED;;+EAE+E;AAC/E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAOzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,UAAU,EAAE,MAAM,GACjB,gBAAgB,EAAE,CA2EpB"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * `task.py` command parsing and brainstorm-window slicing.
3
+ *
4
+ * Pure logic only — boundary signals are recovered from raw shell-call strings;
5
+ * the per-platform raw-JSONL pass that produces those strings lives in the
6
+ * adapters.
7
+ */
8
+ /**
9
+ * Find ALL `task.py create|start` invocations in a single Bash command string.
10
+ * A real Bash invocation can contain several (e.g.
11
+ * `SMOKE=$(task.py create …); task.py start "$SMOKE"`). Returned in source
12
+ * order; each entry's args are bounded to the next `task.py` invocation or
13
+ * end-of-line.
14
+ *
15
+ * False-positive guard: `task.py` must appear at the start of the command,
16
+ * after whitespace, or after a path separator — never embedded inside a flag
17
+ * value like `--slug=task.py-create-foo`.
18
+ */
19
+ export function parseTaskPyCommandsAll(cmd) {
20
+ if (typeof cmd !== "string" || cmd.length === 0)
21
+ return [];
22
+ const all = [];
23
+ const findRe = /(^|[\s/\\])task\.py\s+(create|start)(?:\s+|$)/g;
24
+ const matches = [];
25
+ for (const m of cmd.matchAll(findRe)) {
26
+ const action = m[2];
27
+ const bodyStart = m.index + m[0].length;
28
+ matches.push({ action, bodyStart });
29
+ }
30
+ for (let i = 0; i < matches.length; i++) {
31
+ const cur = matches[i];
32
+ if (!cur)
33
+ continue;
34
+ const next = matches[i + 1];
35
+ const slice = cmd.slice(cur.bodyStart, next?.bodyStart ?? cmd.length);
36
+ const restRaw = (slice.split("\n")[0] ?? "").trim();
37
+ // Reject prose-embedded matches: a bare alphanumeric word followed by
38
+ // another all-letters word is English prose, not a real invocation.
39
+ if (/^[A-Za-z][A-Za-z0-9_-]*\s+[A-Za-z]{2,}\b/.test(restRaw))
40
+ continue;
41
+ const parsed = parseRestOfTaskPyCommand(cur.action, restRaw);
42
+ if (cur.action === "create" &&
43
+ parsed.action === "create" &&
44
+ !parsed.slug &&
45
+ !parsed.titleArg)
46
+ continue;
47
+ if (cur.action === "start" && parsed.action === "start" && !parsed.taskDir)
48
+ continue;
49
+ all.push(parsed);
50
+ }
51
+ return all;
52
+ }
53
+ /** Single-result wrapper — returns the first occurrence, or `null` if none. */
54
+ export function parseTaskPyCommand(cmd) {
55
+ const all = parseTaskPyCommandsAll(cmd);
56
+ return all[0] ?? null;
57
+ }
58
+ function parseRestOfTaskPyCommand(action, restRaw) {
59
+ if (action === "create") {
60
+ const args = splitShellArgs(restRaw);
61
+ let slug;
62
+ let titleArg;
63
+ for (let i = 0; i < args.length; i++) {
64
+ const a = args[i];
65
+ if (a === undefined)
66
+ continue;
67
+ if (a === "--slug" || a === "-s") {
68
+ slug = args[i + 1];
69
+ i++;
70
+ continue;
71
+ }
72
+ if (a.startsWith("--slug=")) {
73
+ slug = a.slice("--slug=".length);
74
+ continue;
75
+ }
76
+ if (a.startsWith("-"))
77
+ continue;
78
+ titleArg ??= a;
79
+ }
80
+ return { action: "create", slug, titleArg };
81
+ }
82
+ const args = splitShellArgs(restRaw);
83
+ let taskDir;
84
+ for (const a of args) {
85
+ if (a.startsWith("-"))
86
+ continue;
87
+ taskDir = a;
88
+ break;
89
+ }
90
+ return { action: "start", taskDir };
91
+ }
92
+ /** Best-effort shell-arg splitter: respects `"…"` / `'…'` quoting, splits on
93
+ * whitespace, treats `;`, `|`, `&`, `(`, `)` as token boundaries, and strips
94
+ * trailing shell-meta cruft (`)};&|>`) from each token. Not a full POSIX
95
+ * parser — sufficient for pulling slugs / paths out of `task.py` invocations. */
96
+ export function splitShellArgs(s) {
97
+ const out = [];
98
+ let cur = "";
99
+ let quote = null;
100
+ const flush = () => {
101
+ if (!cur)
102
+ return;
103
+ const cleaned = cur.replace(/[)};&|>]+$/, "");
104
+ if (cleaned)
105
+ out.push(cleaned);
106
+ cur = "";
107
+ };
108
+ for (const ch of s) {
109
+ if (quote) {
110
+ if (ch === quote) {
111
+ quote = null;
112
+ continue;
113
+ }
114
+ cur += ch;
115
+ continue;
116
+ }
117
+ if (ch === '"' || ch === "'") {
118
+ quote = ch;
119
+ continue;
120
+ }
121
+ if (/\s/.test(ch)) {
122
+ flush();
123
+ continue;
124
+ }
125
+ if (ch === ";" || ch === "|" || ch === "&" || ch === "(" || ch === ")") {
126
+ flush();
127
+ continue;
128
+ }
129
+ cur += ch;
130
+ }
131
+ flush();
132
+ return out;
133
+ }
134
+ /** Derive a slug from a `start` task-dir path like
135
+ * `.trellis/tasks/05-08-mem-phase-slice/` → `mem-phase-slice` (the `MM-DD-`
136
+ * date prefix is stripped so it matches a `--slug` on the paired `create`). */
137
+ export function slugFromTaskDir(p) {
138
+ if (!p)
139
+ return undefined;
140
+ const norm = p.replace(/\\+/g, "/").replace(/\/+$/g, "");
141
+ const parts = norm.split("/").filter(Boolean);
142
+ const last = parts[parts.length - 1];
143
+ if (last === undefined)
144
+ return undefined;
145
+ return last.replace(/^\d{2}-\d{2}-/, "");
146
+ }
147
+ /**
148
+ * Pair `create` → `start` events into brainstorm windows.
149
+ *
150
+ * Pairing strategy:
151
+ * 1. Slug match wins regardless of position.
152
+ * 2. FIFO fallback: remaining creates pair with the next unmatched start
153
+ * appearing after them in event order.
154
+ * 3. Unmatched create → `[create, totalTurns)`.
155
+ * 4. Unmatched start → `[0, start)`.
156
+ *
157
+ * Windows are sorted by `startTurn` ascending for stable output ordering.
158
+ */
159
+ export function buildBrainstormWindows(events, totalTurns) {
160
+ const creates = events
161
+ .map((e, i) => ({ e, i }))
162
+ .filter(({ e }) => e.action === "create");
163
+ const starts = events
164
+ .map((e, i) => ({ e, i }))
165
+ .filter(({ e }) => e.action === "start");
166
+ const usedStartIdx = new Set();
167
+ const usedCreateIdx = new Set();
168
+ const windows = [];
169
+ let windowCounter = 0;
170
+ // Pass 1: pair by slug match.
171
+ for (const { e: createEv, i: ci } of creates) {
172
+ if (!createEv.slug)
173
+ continue;
174
+ const matchIdx = starts.findIndex(({ e, i }) => !usedStartIdx.has(i) && slugFromTaskDir(e.taskDir) === createEv.slug);
175
+ if (matchIdx === -1)
176
+ continue;
177
+ const startEntry = starts[matchIdx];
178
+ if (!startEntry)
179
+ continue;
180
+ usedStartIdx.add(startEntry.i);
181
+ usedCreateIdx.add(ci);
182
+ pushWindow(windows, createEv.turnIndex, startEntry.e.turnIndex, createEv.slug, ++windowCounter);
183
+ }
184
+ // Pass 2: FIFO pair remaining creates with later starts.
185
+ for (const { e: createEv, i: ci } of creates) {
186
+ if (usedCreateIdx.has(ci))
187
+ continue;
188
+ const pairedStart = starts.find(({ i }) => !usedStartIdx.has(i) && i > ci);
189
+ if (pairedStart) {
190
+ usedStartIdx.add(pairedStart.i);
191
+ usedCreateIdx.add(ci);
192
+ const slug = createEv.slug ?? slugFromTaskDir(pairedStart.e.taskDir);
193
+ pushWindow(windows, createEv.turnIndex, pairedStart.e.turnIndex, slug, ++windowCounter);
194
+ }
195
+ else {
196
+ usedCreateIdx.add(ci);
197
+ pushWindow(windows, createEv.turnIndex, totalTurns, createEv.slug, ++windowCounter);
198
+ }
199
+ }
200
+ // Pass 3: unmatched starts → [0, start).
201
+ for (const { e: startEv, i } of starts) {
202
+ if (usedStartIdx.has(i))
203
+ continue;
204
+ pushWindow(windows, 0, startEv.turnIndex, slugFromTaskDir(startEv.taskDir), ++windowCounter);
205
+ }
206
+ windows.sort((a, b) => a.startTurn - b.startTurn);
207
+ return windows;
208
+ }
209
+ function pushWindow(windows, startTurn, endTurn, slug, counter) {
210
+ // Guard against malformed windows (start before create due to event
211
+ // interleave) rather than emitting a negative slice.
212
+ if (endTurn < startTurn)
213
+ return;
214
+ windows.push({
215
+ label: slug ?? `window-${counter}`,
216
+ startTurn,
217
+ endTurn,
218
+ });
219
+ }
220
+ //# sourceMappingURL=phase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase.js","sourceRoot":"","sources":["../../src/mem/phase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Project aggregation: distinct session cwds with last-active timestamp and
3
+ * per-platform counts.
4
+ */
5
+ import type { ListMemProjectsOptions, MemProjectSummary } from "./types.js";
6
+ /**
7
+ * Aggregate distinct project cwds across every platform. Always scans
8
+ * globally (cwd scoping is dropped) — `since` / `until` / `platform` still
9
+ * apply. Results are sorted by `last_active` descending; the caller decides
10
+ * any display cap.
11
+ */
12
+ export declare function listMemProjects(options?: ListMemProjectsOptions): MemProjectSummary[];
13
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/mem/projects.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,iBAAiB,EAAE,CA0BrB"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Project aggregation: distinct session cwds with last-active timestamp and
3
+ * per-platform counts.
4
+ */
5
+ import { listAll, resolveFilter, WIDE_LIMIT } from "./sessions.js";
6
+ /**
7
+ * Aggregate distinct project cwds across every platform. Always scans
8
+ * globally (cwd scoping is dropped) — `since` / `until` / `platform` still
9
+ * apply. Results are sorted by `last_active` descending; the caller decides
10
+ * any display cap.
11
+ */
12
+ export function listMemProjects(options) {
13
+ const f = resolveFilter(options?.filter);
14
+ const all = listAll({ ...f, cwd: undefined, limit: WIDE_LIMIT });
15
+ const byCwd = new Map();
16
+ for (const s of all) {
17
+ if (!s.cwd)
18
+ continue;
19
+ const ts = s.updated ?? s.created ?? "";
20
+ let agg = byCwd.get(s.cwd);
21
+ if (!agg) {
22
+ agg = {
23
+ cwd: s.cwd,
24
+ last_active: ts,
25
+ sessions: 0,
26
+ by_platform: { claude: 0, codex: 0, opencode: 0 },
27
+ };
28
+ byCwd.set(s.cwd, agg);
29
+ }
30
+ agg.sessions++;
31
+ agg.by_platform[s.platform]++;
32
+ if (ts > agg.last_active)
33
+ agg.last_active = ts;
34
+ }
35
+ return [...byCwd.values()].sort((a, b) => b.last_active.localeCompare(a.last_active));
36
+ }
37
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/mem/projects.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGnE;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAgC;IAEhC,MAAM,CAAC,GAAG,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IAEjE,MAAM,KAAK,GAAG,IAAI,GAAG,EAA6B,CAAC;IACnD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,CAAC,CAAC,GAAG;YAAE,SAAS;QACrB,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;QACxC,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG;gBACJ,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,WAAW,EAAE,EAAE;gBACf,QAAQ,EAAE,CAAC;gBACX,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;aAClD,CAAC;YACF,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxB,CAAC;QACD,GAAG,CAAC,QAAQ,EAAE,CAAC;QACf,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,IAAI,EAAE,GAAG,GAAG,CAAC,WAAW;YAAE,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC;IACjD,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACvC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAC3C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Search scoring and text matching over cleaned dialogue.
3
+ */
4
+ import type { DialogueTurn, SearchHit } from "./types.js";
5
+ /**
6
+ * Weighted-density relevance score:
7
+ * `(3 * userCount + asstCount) / totalTurns`
8
+ * Higher = the session is more topically concentrated on the query AND the
9
+ * user themselves brought it up (user hits weighted ×3 — the user's own words
10
+ * anchor "what they actually cared about"; assistant elaboration is downstream
11
+ * noise). Normalized by `totalTurns` so a tight short session can outrank a
12
+ * sprawling long one.
13
+ */
14
+ export declare function relevanceScore(h: SearchHit): number;
15
+ /** Find the paragraph-aligned chunk surrounding a hit position. A "chunk" is
16
+ * the contiguous text bounded by the nearest blank-line breaks (`\n\n`) on
17
+ * either side. If the natural paragraph exceeds `maxChars`, fall back to a
18
+ * centered char window — and report the truncation so callers can mark it. */
19
+ export declare function chunkAround(text: string, hitIdx: number, maxChars: number): {
20
+ start: number;
21
+ end: number;
22
+ truncated: boolean;
23
+ };
24
+ /**
25
+ * Multi-token AND grep over cleaned dialogue. Whitespace-split tokens; a turn
26
+ * matches iff every token (case-insensitive) appears in it. `count` is the
27
+ * total occurrence count across all tokens within matching turns. Excerpts are
28
+ * paragraph-aligned chunks around each hit, deduped by chunk start; user-role
29
+ * chunks are listed before assistant chunks.
30
+ */
31
+ export declare function searchInDialogue(turns: readonly DialogueTurn[], kw: string, maxExcerpts?: number, chunkChars?: number): SearchHit;
32
+ //# sourceMappingURL=search.d.ts.map