@pennixrv/trellis-core 0.6.17

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 (218) 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 +109 -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 +52 -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 +74 -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 +65 -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 +215 -0
  79. package/dist/channel/internal/store/events.d.ts.map +1 -0
  80. package/dist/channel/internal/store/events.js +209 -0
  81. package/dist/channel/internal/store/events.js.map +1 -0
  82. package/dist/channel/internal/store/filter.d.ts +21 -0
  83. package/dist/channel/internal/store/filter.d.ts.map +1 -0
  84. package/dist/channel/internal/store/filter.js +75 -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 +57 -0
  95. package/dist/channel/internal/store/paths.d.ts.map +1 -0
  96. package/dist/channel/internal/store/paths.js +264 -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 +23 -0
  103. package/dist/channel/internal/store/seq.d.ts.map +1 -0
  104. package/dist/channel/internal/store/seq.js +175 -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 +129 -0
  113. package/dist/channel/internal/store/watch.js.map +1 -0
  114. package/dist/channel/internal/store/worker-state.d.ts +56 -0
  115. package/dist/channel/internal/store/worker-state.d.ts.map +1 -0
  116. package/dist/channel/internal/store/worker-state.js +220 -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 +209 -0
  125. package/dist/mem/adapters/claude.js.map +1 -0
  126. package/dist/mem/adapters/codex.d.ts +55 -0
  127. package/dist/mem/adapters/codex.d.ts.map +1 -0
  128. package/dist/mem/adapters/codex.js +344 -0
  129. package/dist/mem/adapters/codex.js.map +1 -0
  130. package/dist/mem/adapters/grok.d.ts +41 -0
  131. package/dist/mem/adapters/grok.d.ts.map +1 -0
  132. package/dist/mem/adapters/grok.js +202 -0
  133. package/dist/mem/adapters/grok.js.map +1 -0
  134. package/dist/mem/adapters/opencode.d.ts +35 -0
  135. package/dist/mem/adapters/opencode.d.ts.map +1 -0
  136. package/dist/mem/adapters/opencode.js +437 -0
  137. package/dist/mem/adapters/opencode.js.map +1 -0
  138. package/dist/mem/adapters/pi.d.ts +24 -0
  139. package/dist/mem/adapters/pi.d.ts.map +1 -0
  140. package/dist/mem/adapters/pi.js +290 -0
  141. package/dist/mem/adapters/pi.js.map +1 -0
  142. package/dist/mem/adapters/zcode.d.ts +76 -0
  143. package/dist/mem/adapters/zcode.d.ts.map +1 -0
  144. package/dist/mem/adapters/zcode.js +434 -0
  145. package/dist/mem/adapters/zcode.js.map +1 -0
  146. package/dist/mem/context.d.ts +23 -0
  147. package/dist/mem/context.d.ts.map +1 -0
  148. package/dist/mem/context.js +120 -0
  149. package/dist/mem/context.js.map +1 -0
  150. package/dist/mem/dialogue.d.ts +32 -0
  151. package/dist/mem/dialogue.d.ts.map +1 -0
  152. package/dist/mem/dialogue.js +0 -0
  153. package/dist/mem/dialogue.js.map +1 -0
  154. package/dist/mem/filter.d.ts +31 -0
  155. package/dist/mem/filter.d.ts.map +1 -0
  156. package/dist/mem/filter.js +66 -0
  157. package/dist/mem/filter.js.map +1 -0
  158. package/dist/mem/index.d.ts +18 -0
  159. package/dist/mem/index.d.ts.map +1 -0
  160. package/dist/mem/index.js +17 -0
  161. package/dist/mem/index.js.map +1 -0
  162. package/dist/mem/internal/jsonl.d.ts +35 -0
  163. package/dist/mem/internal/jsonl.d.ts.map +1 -0
  164. package/dist/mem/internal/jsonl.js +125 -0
  165. package/dist/mem/internal/jsonl.js.map +1 -0
  166. package/dist/mem/internal/paths.d.ts +67 -0
  167. package/dist/mem/internal/paths.d.ts.map +1 -0
  168. package/dist/mem/internal/paths.js +194 -0
  169. package/dist/mem/internal/paths.js.map +1 -0
  170. package/dist/mem/internal/sqlite-readonly.d.ts +77 -0
  171. package/dist/mem/internal/sqlite-readonly.d.ts.map +1 -0
  172. package/dist/mem/internal/sqlite-readonly.js +797 -0
  173. package/dist/mem/internal/sqlite-readonly.js.map +1 -0
  174. package/dist/mem/phase.d.ts +45 -0
  175. package/dist/mem/phase.d.ts.map +1 -0
  176. package/dist/mem/phase.js +220 -0
  177. package/dist/mem/phase.js.map +1 -0
  178. package/dist/mem/projects.d.ts +13 -0
  179. package/dist/mem/projects.d.ts.map +1 -0
  180. package/dist/mem/projects.js +47 -0
  181. package/dist/mem/projects.js.map +1 -0
  182. package/dist/mem/search.d.ts +39 -0
  183. package/dist/mem/search.d.ts.map +1 -0
  184. package/dist/mem/search.js +133 -0
  185. package/dist/mem/search.js.map +1 -0
  186. package/dist/mem/sessions.d.ts +38 -0
  187. package/dist/mem/sessions.d.ts.map +1 -0
  188. package/dist/mem/sessions.js +318 -0
  189. package/dist/mem/sessions.js.map +1 -0
  190. package/dist/mem/types.d.ts +188 -0
  191. package/dist/mem/types.d.ts.map +1 -0
  192. package/dist/mem/types.js +10 -0
  193. package/dist/mem/types.js.map +1 -0
  194. package/dist/task/index.d.ts +9 -0
  195. package/dist/task/index.d.ts.map +1 -0
  196. package/dist/task/index.js +9 -0
  197. package/dist/task/index.js.map +1 -0
  198. package/dist/task/paths.d.ts +37 -0
  199. package/dist/task/paths.d.ts.map +1 -0
  200. package/dist/task/paths.js +49 -0
  201. package/dist/task/paths.js.map +1 -0
  202. package/dist/task/phase.d.ts +27 -0
  203. package/dist/task/phase.d.ts.map +1 -0
  204. package/dist/task/phase.js +24 -0
  205. package/dist/task/phase.js.map +1 -0
  206. package/dist/task/records.d.ts +39 -0
  207. package/dist/task/records.d.ts.map +1 -0
  208. package/dist/task/records.js +89 -0
  209. package/dist/task/records.js.map +1 -0
  210. package/dist/task/schema.d.ts +77 -0
  211. package/dist/task/schema.d.ts.map +1 -0
  212. package/dist/task/schema.js +220 -0
  213. package/dist/task/schema.js.map +1 -0
  214. package/dist/testing/index.d.ts +2 -0
  215. package/dist/testing/index.d.ts.map +1 -0
  216. package/dist/testing/index.js +4 -0
  217. package/dist/testing/index.js.map +1 -0
  218. package/package.json +78 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * If `events.jsonl` ends mid-record (no trailing newline — ENOSPC or
3
+ * SIGKILL during append), truncate to the last complete line. A complete
4
+ * JSONL record is written as stringify(event) plus a trailing newline, so
5
+ * a missing final newline is the torn-tail signal. Complete but
6
+ * unparseable lines are left intact — that is mid-file damage, not a
7
+ * torn tail.
8
+ *
9
+ * Caller must hold the channel lock.
10
+ */
11
+ export declare function truncateIncompleteTail(jsonlPath: string): Promise<void>;
12
+ /**
13
+ * Compute the next seq to assign by reconciling the `.seq` sidecar with
14
+ * the JSONL tail. Repairs the sidecar when it is missing, corrupted,
15
+ * lower than the JSONL tail, or ahead of the JSONL tail (for example,
16
+ * after manual corruption or a stale future reservation).
17
+ *
18
+ * Caller must hold the channel lock when invoking this and the
19
+ * subsequent JSONL append + sidecar write.
20
+ */
21
+ export declare function reconcileSeq(jsonlPath: string, sidecarPath: string): Promise<number>;
22
+ export declare function writeSidecar(sidecarPath: string, seq: number): Promise<void>;
23
+ //# sourceMappingURL=seq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seq.d.ts","sourceRoot":"","sources":["../../../../src/channel/internal/store/seq.ts"],"names":[],"mappings":"AAgGA;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B7E;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAKf"}
@@ -0,0 +1,175 @@
1
+ import fs from "node:fs";
2
+ import fsp from "node:fs/promises";
3
+ import path from "node:path";
4
+ const READ_TAIL_BYTES = 4096;
5
+ const TAIL_SCAN_CHUNK = 64 * 1024;
6
+ /** Parse the sidecar file content. Returns null on missing / non-integer. */
7
+ function parseSidecar(text) {
8
+ const trimmed = text.trim();
9
+ if (!trimmed)
10
+ return null;
11
+ // Reject leading +/-/0x/whitespace permutations; require pure digits.
12
+ if (!/^[0-9]+$/.test(trimmed))
13
+ return null;
14
+ const n = Number(trimmed);
15
+ if (!Number.isFinite(n) || n < 0)
16
+ return null;
17
+ return n;
18
+ }
19
+ async function readSidecar(sidecarPath) {
20
+ if (!fs.existsSync(sidecarPath))
21
+ return null;
22
+ try {
23
+ const text = await fsp.readFile(sidecarPath, "utf-8");
24
+ return parseSidecar(text);
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * Read the last seq value from the JSONL file by tailing the end of the
32
+ * file without loading the entire content. Returns 0 when the file is
33
+ * absent or empty. Throws when the file has content but no recoverable
34
+ * seq, because guessing would risk duplicate seq assignment.
35
+ *
36
+ * Falls back to a full-scan when the tail cannot establish a max seq
37
+ * (e.g. last event spans the tail window or every line is corrupt).
38
+ */
39
+ async function readLastJsonlSeq(jsonlPath) {
40
+ if (!fs.existsSync(jsonlPath))
41
+ return 0;
42
+ let stat;
43
+ try {
44
+ stat = await fsp.stat(jsonlPath);
45
+ }
46
+ catch {
47
+ return 0;
48
+ }
49
+ if (stat.size === 0)
50
+ return 0;
51
+ const seqFromBuffer = (buf) => {
52
+ const text = buf.toString("utf-8");
53
+ const lines = text.split("\n");
54
+ for (let i = lines.length - 1; i >= 0; i--) {
55
+ const line = lines[i].trim();
56
+ if (!line)
57
+ continue;
58
+ try {
59
+ const parsed = JSON.parse(line);
60
+ if (typeof parsed.seq === "number" && Number.isFinite(parsed.seq)) {
61
+ return parsed.seq;
62
+ }
63
+ }
64
+ catch {
65
+ continue;
66
+ }
67
+ }
68
+ return null;
69
+ };
70
+ // Tail-read first.
71
+ const tailLen = Math.min(stat.size, READ_TAIL_BYTES);
72
+ const fh = await fsp.open(jsonlPath, "r");
73
+ try {
74
+ const buf = Buffer.alloc(tailLen);
75
+ await fh.read(buf, 0, tailLen, stat.size - tailLen);
76
+ // Find the first newline so we don't try to JSON.parse a partial
77
+ // first line that the tail window happened to slice mid-event.
78
+ let usable = buf;
79
+ if (stat.size > tailLen) {
80
+ const firstNewline = buf.indexOf(0x0a);
81
+ usable = firstNewline >= 0 ? buf.subarray(firstNewline + 1) : Buffer.alloc(0);
82
+ }
83
+ if (usable.length > 0) {
84
+ const found = seqFromBuffer(usable);
85
+ if (found !== null)
86
+ return found;
87
+ }
88
+ }
89
+ finally {
90
+ await fh.close();
91
+ }
92
+ // Tail did not produce a seq — fall back to a full scan.
93
+ const text = await fsp.readFile(jsonlPath, "utf-8");
94
+ const found = seqFromBuffer(Buffer.from(text));
95
+ if (found !== null)
96
+ return found;
97
+ if (text.split("\n").some((line) => line.trim() !== "")) {
98
+ throw new Error(`Unable to recover channel seq from ${jsonlPath}`);
99
+ }
100
+ return 0;
101
+ }
102
+ /**
103
+ * If `events.jsonl` ends mid-record (no trailing newline — ENOSPC or
104
+ * SIGKILL during append), truncate to the last complete line. A complete
105
+ * JSONL record is written as stringify(event) plus a trailing newline, so
106
+ * a missing final newline is the torn-tail signal. Complete but
107
+ * unparseable lines are left intact — that is mid-file damage, not a
108
+ * torn tail.
109
+ *
110
+ * Caller must hold the channel lock.
111
+ */
112
+ export async function truncateIncompleteTail(jsonlPath) {
113
+ if (!fs.existsSync(jsonlPath))
114
+ return;
115
+ const fh = await fsp.open(jsonlPath, "r+");
116
+ try {
117
+ const stat = await fh.stat();
118
+ if (stat.size === 0)
119
+ return;
120
+ const lastByte = Buffer.alloc(1);
121
+ await fh.read(lastByte, 0, 1, stat.size - 1);
122
+ if (lastByte[0] === 0x0a)
123
+ return;
124
+ let offset = stat.size;
125
+ while (offset > 0) {
126
+ const start = Math.max(0, offset - TAIL_SCAN_CHUNK);
127
+ const length = offset - start;
128
+ const buf = Buffer.alloc(length);
129
+ await fh.read(buf, 0, length, start);
130
+ const newline = buf.lastIndexOf(0x0a);
131
+ if (newline >= 0) {
132
+ await fh.truncate(start + newline + 1);
133
+ return;
134
+ }
135
+ offset = start;
136
+ }
137
+ await fh.truncate(0);
138
+ }
139
+ finally {
140
+ await fh.close();
141
+ }
142
+ }
143
+ /**
144
+ * Compute the next seq to assign by reconciling the `.seq` sidecar with
145
+ * the JSONL tail. Repairs the sidecar when it is missing, corrupted,
146
+ * lower than the JSONL tail, or ahead of the JSONL tail (for example,
147
+ * after manual corruption or a stale future reservation).
148
+ *
149
+ * Caller must hold the channel lock when invoking this and the
150
+ * subsequent JSONL append + sidecar write.
151
+ */
152
+ export async function reconcileSeq(jsonlPath, sidecarPath) {
153
+ const sidecar = await readSidecar(sidecarPath);
154
+ const jsonlTail = await readLastJsonlSeq(jsonlPath);
155
+ // Decision matrix:
156
+ // sidecar = N, jsonl = N -> normal; next = N+1
157
+ // sidecar = N, jsonl = N+k -> sidecar stale; repair forward to N+k
158
+ // sidecar = N, jsonl = N-k -> sidecar ahead of JSONL;
159
+ // rewind to JSONL tail so we never
160
+ // leave a seq gap from a stale
161
+ // reservation
162
+ // sidecar = null, jsonl = M -> lazy rebuild; use jsonl tail
163
+ const last = jsonlTail;
164
+ if (sidecar !== last) {
165
+ await writeSidecar(sidecarPath, last);
166
+ }
167
+ return last;
168
+ }
169
+ export async function writeSidecar(sidecarPath, seq) {
170
+ await fsp.mkdir(path.dirname(sidecarPath), { recursive: true });
171
+ const tmp = `${sidecarPath}.tmp.${process.pid}.${Date.now()}`;
172
+ await fsp.writeFile(tmp, `${seq}\n`, "utf-8");
173
+ await fsp.rename(tmp, sidecarPath);
174
+ }
175
+ //# sourceMappingURL=seq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seq.js","sourceRoot":"","sources":["../../../../src/channel/internal/store/seq.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { type ChannelEvent, type ContextChannelEvent, type ThreadChannelEvent } from "./events.js";
2
+ import { type ContextEntry } from "./schema.js";
3
+ export interface ThreadState {
4
+ thread: string;
5
+ title?: string;
6
+ status: string;
7
+ labels: string[];
8
+ assignees: string[];
9
+ description?: string;
10
+ context?: ContextEntry[];
11
+ summary?: string;
12
+ openedAt?: string;
13
+ updatedAt?: string;
14
+ lastSeq: number;
15
+ comments: number;
16
+ /** Previous thread keys after rename. Resolved-from-old-key consumers
17
+ * use this set to recover history that references the rename source. */
18
+ aliases: string[];
19
+ }
20
+ /**
21
+ * Resolve thread aliases over an event stream. Returns a function that
22
+ * maps any (current or previous) thread key to its current canonical
23
+ * key, plus the set of historical aliases for each current key.
24
+ */
25
+ export interface ThreadAliasResolver {
26
+ resolve(key: string): string;
27
+ aliasesFor(currentKey: string): string[];
28
+ }
29
+ export declare function buildThreadAliasResolver(events: ChannelEvent[]): ThreadAliasResolver;
30
+ export declare function reduceThreads(events: ChannelEvent[]): ThreadState[];
31
+ /**
32
+ * Return the timeline events that belong to a given thread (or any of
33
+ * its rename aliases), in seq order. Includes thread events and
34
+ * thread-targeted context events.
35
+ */
36
+ export declare function collectThreadTimeline(events: ChannelEvent[], threadKey: string): (ThreadChannelEvent | ContextChannelEvent)[];
37
+ //# sourceMappingURL=thread-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-state.d.ts","sourceRoot":"","sources":["../../../../src/channel/internal/store/thread-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB;6EACyE;IACzE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAMD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1C;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EAAE,GACrB,mBAAmB,CAsDrB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,WAAW,EAAE,CAgFnE;AAoDD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EAAE,EACtB,SAAS,EAAE,MAAM,GAChB,CAAC,kBAAkB,GAAG,mBAAmB,CAAC,EAAE,CAgB9C"}
@@ -0,0 +1,206 @@
1
+ import { isContextEvent, isThreadEvent, } from "./events.js";
2
+ import { asContextEntries, asStringArray, contextEntryKey, } from "./schema.js";
3
+ export function buildThreadAliasResolver(events) {
4
+ // Map from any historical key -> current key (chain-flattened).
5
+ const aliasToCurrent = new Map();
6
+ // Reverse index: current key -> set of historical aliases (excluding self).
7
+ const aliasesByCurrent = new Map();
8
+ const currentFor = (key) => {
9
+ let cur = aliasToCurrent.get(key) ?? key;
10
+ // Flatten any chain that may form if the same key was renamed more
11
+ // than once. We rebuild on each call so callers do not see stale
12
+ // pointers when this function is called mid-stream.
13
+ const seen = new Set();
14
+ while (aliasToCurrent.has(cur) && !seen.has(cur)) {
15
+ seen.add(cur);
16
+ cur = aliasToCurrent.get(cur);
17
+ }
18
+ return cur;
19
+ };
20
+ for (const ev of events) {
21
+ if (!isThreadEvent(ev) || ev.action !== "rename")
22
+ continue;
23
+ const newKey = typeof ev.newThread === "string" ? ev.newThread.trim() : undefined;
24
+ const oldKey = ev.thread;
25
+ if (!newKey || !oldKey || newKey === oldKey)
26
+ continue;
27
+ const oldCurrent = currentFor(oldKey);
28
+ const targetCurrent = currentFor(newKey);
29
+ if (oldCurrent === targetCurrent)
30
+ continue;
31
+ // Migrate the alias group rooted at `oldCurrent` onto `targetCurrent`.
32
+ const movingAliases = aliasesByCurrent.get(oldCurrent) ?? new Set();
33
+ movingAliases.add(oldCurrent);
34
+ aliasesByCurrent.delete(oldCurrent);
35
+ const targetAliases = aliasesByCurrent.get(targetCurrent) ?? new Set();
36
+ for (const alias of movingAliases) {
37
+ if (alias !== targetCurrent)
38
+ targetAliases.add(alias);
39
+ aliasToCurrent.set(alias, targetCurrent);
40
+ }
41
+ aliasesByCurrent.set(targetCurrent, targetAliases);
42
+ }
43
+ return {
44
+ resolve(key) {
45
+ return currentFor(key);
46
+ },
47
+ aliasesFor(currentKey) {
48
+ const set = aliasesByCurrent.get(currentKey);
49
+ return set ? [...set] : [];
50
+ },
51
+ };
52
+ }
53
+ export function reduceThreads(events) {
54
+ const resolver = buildThreadAliasResolver(events);
55
+ const states = new Map();
56
+ const ensure = (key, seq) => {
57
+ const current = states.get(key);
58
+ if (current)
59
+ return current;
60
+ const fresh = {
61
+ thread: key,
62
+ status: "open",
63
+ labels: [],
64
+ assignees: [],
65
+ lastSeq: seq,
66
+ comments: 0,
67
+ aliases: [],
68
+ contextMap: new Map(),
69
+ };
70
+ states.set(key, fresh);
71
+ return fresh;
72
+ };
73
+ for (const ev of events) {
74
+ if (isThreadEvent(ev)) {
75
+ const current = resolver.resolve(ev.thread);
76
+ const state = ensure(current, ev.seq);
77
+ if (typeof ev.ts === "string")
78
+ state.updatedAt = ev.ts;
79
+ if (!state.openedAt && typeof ev.ts === "string") {
80
+ state.openedAt = ev.ts;
81
+ }
82
+ state.lastSeq = ev.seq;
83
+ applyThreadAction(state, ev);
84
+ continue;
85
+ }
86
+ if (isContextEvent(ev) && ev.target === "thread" && ev.thread) {
87
+ const current = resolver.resolve(ev.thread);
88
+ const state = states.get(current);
89
+ if (!state)
90
+ continue;
91
+ const entries = asContextEntries(ev.context);
92
+ if (!entries)
93
+ continue;
94
+ if (ev.action === "add") {
95
+ for (const entry of entries) {
96
+ state.contextMap.set(contextEntryKey(entry), entry);
97
+ }
98
+ }
99
+ else if (ev.action === "delete") {
100
+ for (const entry of entries) {
101
+ state.contextMap.delete(contextEntryKey(entry));
102
+ }
103
+ }
104
+ if (typeof ev.ts === "string")
105
+ state.updatedAt = ev.ts;
106
+ state.lastSeq = ev.seq;
107
+ continue;
108
+ }
109
+ }
110
+ return [...states.entries()]
111
+ .map(([currentKey, state]) => {
112
+ const aliases = resolver.aliasesFor(currentKey);
113
+ const context = state.contextMap.size > 0 ? [...state.contextMap.values()] : undefined;
114
+ const result = {
115
+ thread: state.thread,
116
+ ...(state.title !== undefined ? { title: state.title } : {}),
117
+ status: state.status,
118
+ labels: state.labels,
119
+ assignees: state.assignees,
120
+ ...(state.description !== undefined
121
+ ? { description: state.description }
122
+ : {}),
123
+ ...(context !== undefined ? { context } : {}),
124
+ ...(state.summary !== undefined ? { summary: state.summary } : {}),
125
+ ...(state.openedAt !== undefined ? { openedAt: state.openedAt } : {}),
126
+ ...(state.updatedAt !== undefined ? { updatedAt: state.updatedAt } : {}),
127
+ lastSeq: state.lastSeq,
128
+ comments: state.comments,
129
+ aliases,
130
+ };
131
+ return result;
132
+ })
133
+ .sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""));
134
+ }
135
+ function applyThreadAction(current, ev) {
136
+ switch (ev.action) {
137
+ case "opened":
138
+ current.status = typeof ev.status === "string" ? ev.status : "open";
139
+ if (typeof ev.title === "string")
140
+ current.title = ev.title;
141
+ if (typeof ev.description === "string") {
142
+ current.description = ev.description;
143
+ }
144
+ {
145
+ const initial = asContextEntries(ev.context) ?? asContextEntries(ev.linkedContext);
146
+ if (initial) {
147
+ current.contextMap.clear();
148
+ for (const entry of initial) {
149
+ current.contextMap.set(contextEntryKey(entry), entry);
150
+ }
151
+ }
152
+ }
153
+ current.labels = asStringArray(ev.labels) ?? current.labels;
154
+ current.assignees = asStringArray(ev.assignees) ?? current.assignees;
155
+ return;
156
+ case "comment":
157
+ current.comments += 1;
158
+ return;
159
+ case "status":
160
+ if (typeof ev.status === "string")
161
+ current.status = ev.status;
162
+ return;
163
+ case "labels":
164
+ current.labels = asStringArray(ev.labels) ?? current.labels;
165
+ return;
166
+ case "assignees":
167
+ current.assignees = asStringArray(ev.assignees) ?? current.assignees;
168
+ return;
169
+ case "summary":
170
+ if (typeof ev.summary === "string")
171
+ current.summary = ev.summary;
172
+ return;
173
+ case "processed":
174
+ current.status = typeof ev.status === "string" ? ev.status : "processed";
175
+ return;
176
+ case "rename":
177
+ // Rename handled by the alias resolver; nothing to do here.
178
+ return;
179
+ default:
180
+ return;
181
+ }
182
+ }
183
+ /**
184
+ * Return the timeline events that belong to a given thread (or any of
185
+ * its rename aliases), in seq order. Includes thread events and
186
+ * thread-targeted context events.
187
+ */
188
+ export function collectThreadTimeline(events, threadKey) {
189
+ const resolver = buildThreadAliasResolver(events);
190
+ const current = resolver.resolve(threadKey);
191
+ const aliases = new Set([current, ...resolver.aliasesFor(current)]);
192
+ const out = [];
193
+ for (const ev of events) {
194
+ if (isThreadEvent(ev)) {
195
+ if (aliases.has(ev.thread))
196
+ out.push(ev);
197
+ continue;
198
+ }
199
+ if (isContextEvent(ev) && ev.target === "thread" && ev.thread) {
200
+ if (aliases.has(ev.thread))
201
+ out.push(ev);
202
+ }
203
+ }
204
+ return out;
205
+ }
206
+ //# sourceMappingURL=thread-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-state.js","sourceRoot":"","sources":["../../../../src/channel/internal/store/thread-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ChannelEvent } from "./events.js";
2
+ import { type ChannelEventFilter } from "./filter.js";
3
+ export type WatchFilter = ChannelEventFilter;
4
+ export declare function watchEvents(channelName: string, filter: WatchFilter, opts?: {
5
+ signal?: AbortSignal;
6
+ fromStart?: boolean;
7
+ sinceSeq?: number;
8
+ project?: string;
9
+ }): AsyncGenerator<ChannelEvent, void, unknown>;
10
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../../src/channel/internal/store/watch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAG1E,MAAM,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAmD7C,wBAAuB,WAAW,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE;IACJ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACb,GACL,cAAc,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAiF7C"}
@@ -0,0 +1,129 @@
1
+ import fs from "node:fs";
2
+ import { StringDecoder } from "node:string_decoder";
3
+ import { matchesEventFilter } from "./filter.js";
4
+ import { channelDir, eventsPath } from "./paths.js";
5
+ async function readNewEvents(filePath, state) {
6
+ if (!fs.existsSync(filePath)) {
7
+ state.byteOffset = 0;
8
+ state.carry = "";
9
+ state.decoder = new StringDecoder("utf8");
10
+ return [];
11
+ }
12
+ const stat = await fs.promises.stat(filePath);
13
+ if (stat.size < state.byteOffset) {
14
+ state.byteOffset = 0;
15
+ state.carry = "";
16
+ state.decoder = new StringDecoder("utf8");
17
+ }
18
+ if (stat.size <= state.byteOffset)
19
+ return [];
20
+ const fh = await fs.promises.open(filePath, "r");
21
+ try {
22
+ const length = stat.size - state.byteOffset;
23
+ const buf = Buffer.alloc(length);
24
+ await fh.read(buf, 0, length, state.byteOffset);
25
+ state.byteOffset = stat.size;
26
+ const text = state.carry + state.decoder.write(buf);
27
+ const lines = text.split("\n");
28
+ state.carry = lines.pop() ?? "";
29
+ const events = [];
30
+ for (const line of lines) {
31
+ const t = line.trim();
32
+ if (!t)
33
+ continue;
34
+ try {
35
+ events.push(JSON.parse(t));
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ }
41
+ return events;
42
+ }
43
+ finally {
44
+ await fh.close();
45
+ }
46
+ }
47
+ export async function* watchEvents(channelName, filter, opts = {}) {
48
+ const file = eventsPath(channelName, opts.project);
49
+ if (!fs.existsSync(channelDir(channelName, opts.project))) {
50
+ await fs.promises.mkdir(channelDir(channelName, opts.project), {
51
+ recursive: true,
52
+ });
53
+ }
54
+ let initialOffset = 0;
55
+ if (!opts.fromStart && opts.sinceSeq === undefined) {
56
+ try {
57
+ if (fs.existsSync(file)) {
58
+ initialOffset = (await fs.promises.stat(file)).size;
59
+ }
60
+ }
61
+ catch {
62
+ initialOffset = 0;
63
+ }
64
+ }
65
+ const state = {
66
+ byteOffset: initialOffset,
67
+ carry: "",
68
+ decoder: new StringDecoder("utf8"),
69
+ };
70
+ const sinceSeq = opts.sinceSeq;
71
+ let resolveNext = null;
72
+ const wake = () => {
73
+ if (resolveNext) {
74
+ const r = resolveNext;
75
+ resolveNext = null;
76
+ r();
77
+ }
78
+ };
79
+ let watcher = null;
80
+ try {
81
+ watcher = fs.watch(channelDir(channelName, opts.project), () => wake());
82
+ watcher.on("error", () => {
83
+ try {
84
+ watcher?.close();
85
+ }
86
+ catch {
87
+ // already closed
88
+ }
89
+ watcher = null;
90
+ // Keep the generator alive; the 200ms poll remains the fallback.
91
+ wake();
92
+ });
93
+ }
94
+ catch {
95
+ // ignore — fall back to polling
96
+ }
97
+ const poll = setInterval(wake, 200);
98
+ const abortHandler = () => wake();
99
+ opts.signal?.addEventListener("abort", abortHandler);
100
+ try {
101
+ while (true) {
102
+ if (opts.signal?.aborted)
103
+ return;
104
+ const fresh = await readNewEvents(file, state);
105
+ for (const ev of fresh) {
106
+ if (sinceSeq !== undefined && ev.seq <= sinceSeq)
107
+ continue;
108
+ if (matchesEventFilter(ev, filter))
109
+ yield ev;
110
+ if (opts.signal?.aborted)
111
+ return;
112
+ }
113
+ await new Promise((resolve) => {
114
+ resolveNext = resolve;
115
+ });
116
+ }
117
+ }
118
+ finally {
119
+ clearInterval(poll);
120
+ try {
121
+ watcher?.close();
122
+ }
123
+ catch {
124
+ // already closed
125
+ }
126
+ opts.signal?.removeEventListener("abort", abortHandler);
127
+ }
128
+ }
129
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../../src/channel/internal/store/watch.ts"],"names":[],"mappings":"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"}