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.
- package/LICENSE +235 -0
- package/dist/channel/api/assert.d.ts +3 -0
- package/dist/channel/api/assert.d.ts.map +1 -0
- package/dist/channel/api/assert.js +11 -0
- package/dist/channel/api/assert.js.map +1 -0
- package/dist/channel/api/context.d.ts +21 -0
- package/dist/channel/api/context.d.ts.map +1 -0
- package/dist/channel/api/context.js +99 -0
- package/dist/channel/api/context.js.map +1 -0
- package/dist/channel/api/create.d.ts +9 -0
- package/dist/channel/api/create.d.ts.map +1 -0
- package/dist/channel/api/create.js +104 -0
- package/dist/channel/api/create.js.map +1 -0
- package/dist/channel/api/inbox.d.ts +51 -0
- package/dist/channel/api/inbox.d.ts.map +1 -0
- package/dist/channel/api/inbox.js +176 -0
- package/dist/channel/api/inbox.js.map +1 -0
- package/dist/channel/api/interrupt.d.ts +31 -0
- package/dist/channel/api/interrupt.d.ts.map +1 -0
- package/dist/channel/api/interrupt.js +102 -0
- package/dist/channel/api/interrupt.js.map +1 -0
- package/dist/channel/api/post-thread.d.ts +14 -0
- package/dist/channel/api/post-thread.d.ts.map +1 -0
- package/dist/channel/api/post-thread.js +106 -0
- package/dist/channel/api/post-thread.js.map +1 -0
- package/dist/channel/api/read.d.ts +17 -0
- package/dist/channel/api/read.d.ts.map +1 -0
- package/dist/channel/api/read.js +44 -0
- package/dist/channel/api/read.js.map +1 -0
- package/dist/channel/api/resolve.d.ts +21 -0
- package/dist/channel/api/resolve.d.ts.map +1 -0
- package/dist/channel/api/resolve.js +28 -0
- package/dist/channel/api/resolve.js.map +1 -0
- package/dist/channel/api/runtime.d.ts +70 -0
- package/dist/channel/api/runtime.d.ts.map +1 -0
- package/dist/channel/api/runtime.js +11 -0
- package/dist/channel/api/runtime.js.map +1 -0
- package/dist/channel/api/send.d.ts +4 -0
- package/dist/channel/api/send.d.ts.map +1 -0
- package/dist/channel/api/send.js +44 -0
- package/dist/channel/api/send.js.map +1 -0
- package/dist/channel/api/spawn.d.ts +13 -0
- package/dist/channel/api/spawn.d.ts.map +1 -0
- package/dist/channel/api/spawn.js +54 -0
- package/dist/channel/api/spawn.js.map +1 -0
- package/dist/channel/api/title.d.ts +5 -0
- package/dist/channel/api/title.d.ts.map +1 -0
- package/dist/channel/api/title.js +40 -0
- package/dist/channel/api/title.js.map +1 -0
- package/dist/channel/api/types.d.ts +64 -0
- package/dist/channel/api/types.d.ts.map +1 -0
- package/dist/channel/api/types.js +2 -0
- package/dist/channel/api/types.js.map +1 -0
- package/dist/channel/api/watch-channels.d.ts +40 -0
- package/dist/channel/api/watch-channels.d.ts.map +1 -0
- package/dist/channel/api/watch-channels.js +143 -0
- package/dist/channel/api/watch-channels.js.map +1 -0
- package/dist/channel/api/watch.d.ts +11 -0
- package/dist/channel/api/watch.d.ts.map +1 -0
- package/dist/channel/api/watch.js +17 -0
- package/dist/channel/api/watch.js.map +1 -0
- package/dist/channel/api/workers.d.ts +69 -0
- package/dist/channel/api/workers.d.ts.map +1 -0
- package/dist/channel/api/workers.js +145 -0
- package/dist/channel/api/workers.js.map +1 -0
- package/dist/channel/index.d.ts +38 -0
- package/dist/channel/index.d.ts.map +1 -0
- package/dist/channel/index.js +23 -0
- package/dist/channel/index.js.map +1 -0
- package/dist/channel/internal/store/channel-metadata.d.ts +23 -0
- package/dist/channel/internal/store/channel-metadata.d.ts.map +1 -0
- package/dist/channel/internal/store/channel-metadata.js +94 -0
- package/dist/channel/internal/store/channel-metadata.js.map +1 -0
- package/dist/channel/internal/store/delivery.d.ts +27 -0
- package/dist/channel/internal/store/delivery.d.ts.map +1 -0
- package/dist/channel/internal/store/delivery.js +37 -0
- package/dist/channel/internal/store/delivery.js.map +1 -0
- package/dist/channel/internal/store/events.d.ts +203 -0
- package/dist/channel/internal/store/events.d.ts.map +1 -0
- package/dist/channel/internal/store/events.js +185 -0
- package/dist/channel/internal/store/events.js.map +1 -0
- package/dist/channel/internal/store/filter.d.ts +22 -0
- package/dist/channel/internal/store/filter.d.ts.map +1 -0
- package/dist/channel/internal/store/filter.js +78 -0
- package/dist/channel/internal/store/filter.js.map +1 -0
- package/dist/channel/internal/store/inbox.d.ts +17 -0
- package/dist/channel/internal/store/inbox.d.ts.map +1 -0
- package/dist/channel/internal/store/inbox.js +30 -0
- package/dist/channel/internal/store/inbox.js.map +1 -0
- package/dist/channel/internal/store/lock.d.ts +17 -0
- package/dist/channel/internal/store/lock.d.ts.map +1 -0
- package/dist/channel/internal/store/lock.js +88 -0
- package/dist/channel/internal/store/lock.js.map +1 -0
- package/dist/channel/internal/store/paths.d.ts +43 -0
- package/dist/channel/internal/store/paths.d.ts.map +1 -0
- package/dist/channel/internal/store/paths.js +233 -0
- package/dist/channel/internal/store/paths.js.map +1 -0
- package/dist/channel/internal/store/schema.d.ts +77 -0
- package/dist/channel/internal/store/schema.d.ts.map +1 -0
- package/dist/channel/internal/store/schema.js +127 -0
- package/dist/channel/internal/store/schema.js.map +1 -0
- package/dist/channel/internal/store/seq.d.ts +12 -0
- package/dist/channel/internal/store/seq.d.ts.map +1 -0
- package/dist/channel/internal/store/seq.js +133 -0
- package/dist/channel/internal/store/seq.js.map +1 -0
- package/dist/channel/internal/store/thread-state.d.ts +37 -0
- package/dist/channel/internal/store/thread-state.d.ts.map +1 -0
- package/dist/channel/internal/store/thread-state.js +206 -0
- package/dist/channel/internal/store/thread-state.js.map +1 -0
- package/dist/channel/internal/store/watch.d.ts +10 -0
- package/dist/channel/internal/store/watch.d.ts.map +1 -0
- package/dist/channel/internal/store/watch.js +122 -0
- package/dist/channel/internal/store/watch.js.map +1 -0
- package/dist/channel/internal/store/worker-state.d.ts +49 -0
- package/dist/channel/internal/store/worker-state.d.ts.map +1 -0
- package/dist/channel/internal/store/worker-state.js +207 -0
- package/dist/channel/internal/store/worker-state.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mem/adapters/claude.d.ts +22 -0
- package/dist/mem/adapters/claude.d.ts.map +1 -0
- package/dist/mem/adapters/claude.js +252 -0
- package/dist/mem/adapters/claude.js.map +1 -0
- package/dist/mem/adapters/codex.d.ts +35 -0
- package/dist/mem/adapters/codex.d.ts.map +1 -0
- package/dist/mem/adapters/codex.js +222 -0
- package/dist/mem/adapters/codex.js.map +1 -0
- package/dist/mem/adapters/opencode.d.ts +19 -0
- package/dist/mem/adapters/opencode.d.ts.map +1 -0
- package/dist/mem/adapters/opencode.js +25 -0
- package/dist/mem/adapters/opencode.js.map +1 -0
- package/dist/mem/context.d.ts +23 -0
- package/dist/mem/context.d.ts.map +1 -0
- package/dist/mem/context.js +118 -0
- package/dist/mem/context.js.map +1 -0
- package/dist/mem/dialogue.d.ts +17 -0
- package/dist/mem/dialogue.d.ts.map +1 -0
- package/dist/mem/dialogue.js +51 -0
- package/dist/mem/dialogue.js.map +1 -0
- package/dist/mem/filter.d.ts +31 -0
- package/dist/mem/filter.d.ts.map +1 -0
- package/dist/mem/filter.js +70 -0
- package/dist/mem/filter.js.map +1 -0
- package/dist/mem/index.d.ts +18 -0
- package/dist/mem/index.d.ts.map +1 -0
- package/dist/mem/index.js +17 -0
- package/dist/mem/index.js.map +1 -0
- package/dist/mem/internal/jsonl.d.ts +35 -0
- package/dist/mem/internal/jsonl.d.ts.map +1 -0
- package/dist/mem/internal/jsonl.js +125 -0
- package/dist/mem/internal/jsonl.js.map +1 -0
- package/dist/mem/internal/paths.d.ts +18 -0
- package/dist/mem/internal/paths.d.ts.map +1 -0
- package/dist/mem/internal/paths.js +51 -0
- package/dist/mem/internal/paths.js.map +1 -0
- package/dist/mem/phase.d.ts +45 -0
- package/dist/mem/phase.d.ts.map +1 -0
- package/dist/mem/phase.js +220 -0
- package/dist/mem/phase.js.map +1 -0
- package/dist/mem/projects.d.ts +13 -0
- package/dist/mem/projects.d.ts.map +1 -0
- package/dist/mem/projects.js +37 -0
- package/dist/mem/projects.js.map +1 -0
- package/dist/mem/search.d.ts +32 -0
- package/dist/mem/search.d.ts.map +1 -0
- package/dist/mem/search.js +125 -0
- package/dist/mem/search.js.map +1 -0
- package/dist/mem/sessions.d.ts +37 -0
- package/dist/mem/sessions.d.ts.map +1 -0
- package/dist/mem/sessions.js +270 -0
- package/dist/mem/sessions.js.map +1 -0
- package/dist/mem/types.d.ts +176 -0
- package/dist/mem/types.d.ts.map +1 -0
- package/dist/mem/types.js +10 -0
- package/dist/mem/types.js.map +1 -0
- package/dist/task/index.d.ts +9 -0
- package/dist/task/index.d.ts.map +1 -0
- package/dist/task/index.js +9 -0
- package/dist/task/index.js.map +1 -0
- package/dist/task/paths.d.ts +37 -0
- package/dist/task/paths.d.ts.map +1 -0
- package/dist/task/paths.js +49 -0
- package/dist/task/paths.js.map +1 -0
- package/dist/task/phase.d.ts +27 -0
- package/dist/task/phase.d.ts.map +1 -0
- package/dist/task/phase.js +24 -0
- package/dist/task/phase.js.map +1 -0
- package/dist/task/records.d.ts +39 -0
- package/dist/task/records.d.ts.map +1 -0
- package/dist/task/records.js +89 -0
- package/dist/task/records.js.map +1 -0
- package/dist/task/schema.d.ts +77 -0
- package/dist/task/schema.d.ts.map +1 -0
- package/dist/task/schema.js +220 -0
- package/dist/task/schema.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +4 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
/** Parse the sidecar file content. Returns null on missing / non-integer. */
|
|
6
|
+
function parseSidecar(text) {
|
|
7
|
+
const trimmed = text.trim();
|
|
8
|
+
if (!trimmed)
|
|
9
|
+
return null;
|
|
10
|
+
// Reject leading +/-/0x/whitespace permutations; require pure digits.
|
|
11
|
+
if (!/^[0-9]+$/.test(trimmed))
|
|
12
|
+
return null;
|
|
13
|
+
const n = Number(trimmed);
|
|
14
|
+
if (!Number.isFinite(n) || n < 0)
|
|
15
|
+
return null;
|
|
16
|
+
return n;
|
|
17
|
+
}
|
|
18
|
+
async function readSidecar(sidecarPath) {
|
|
19
|
+
if (!fs.existsSync(sidecarPath))
|
|
20
|
+
return null;
|
|
21
|
+
try {
|
|
22
|
+
const text = await fsp.readFile(sidecarPath, "utf-8");
|
|
23
|
+
return parseSidecar(text);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read the last seq value from the JSONL file by tailing the end of the
|
|
31
|
+
* file without loading the entire content. Returns 0 when the file is
|
|
32
|
+
* absent or empty. Throws when the file has content but no recoverable
|
|
33
|
+
* seq, because guessing would risk duplicate seq assignment.
|
|
34
|
+
*
|
|
35
|
+
* Falls back to a full-scan when the tail cannot establish a max seq
|
|
36
|
+
* (e.g. last event spans the tail window or every line is corrupt).
|
|
37
|
+
*/
|
|
38
|
+
async function readLastJsonlSeq(jsonlPath) {
|
|
39
|
+
if (!fs.existsSync(jsonlPath))
|
|
40
|
+
return 0;
|
|
41
|
+
let stat;
|
|
42
|
+
try {
|
|
43
|
+
stat = await fsp.stat(jsonlPath);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
if (stat.size === 0)
|
|
49
|
+
return 0;
|
|
50
|
+
const seqFromBuffer = (buf) => {
|
|
51
|
+
const text = buf.toString("utf-8");
|
|
52
|
+
const lines = text.split("\n");
|
|
53
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
54
|
+
const line = lines[i].trim();
|
|
55
|
+
if (!line)
|
|
56
|
+
continue;
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(line);
|
|
59
|
+
if (typeof parsed.seq === "number" && Number.isFinite(parsed.seq)) {
|
|
60
|
+
return parsed.seq;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
};
|
|
69
|
+
// Tail-read first.
|
|
70
|
+
const tailLen = Math.min(stat.size, READ_TAIL_BYTES);
|
|
71
|
+
const fh = await fsp.open(jsonlPath, "r");
|
|
72
|
+
try {
|
|
73
|
+
const buf = Buffer.alloc(tailLen);
|
|
74
|
+
await fh.read(buf, 0, tailLen, stat.size - tailLen);
|
|
75
|
+
// Find the first newline so we don't try to JSON.parse a partial
|
|
76
|
+
// first line that the tail window happened to slice mid-event.
|
|
77
|
+
let usable = buf;
|
|
78
|
+
if (stat.size > tailLen) {
|
|
79
|
+
const firstNewline = buf.indexOf(0x0a);
|
|
80
|
+
usable = firstNewline >= 0 ? buf.subarray(firstNewline + 1) : Buffer.alloc(0);
|
|
81
|
+
}
|
|
82
|
+
if (usable.length > 0) {
|
|
83
|
+
const found = seqFromBuffer(usable);
|
|
84
|
+
if (found !== null)
|
|
85
|
+
return found;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
await fh.close();
|
|
90
|
+
}
|
|
91
|
+
// Tail did not produce a seq — fall back to a full scan.
|
|
92
|
+
const text = await fsp.readFile(jsonlPath, "utf-8");
|
|
93
|
+
const found = seqFromBuffer(Buffer.from(text));
|
|
94
|
+
if (found !== null)
|
|
95
|
+
return found;
|
|
96
|
+
if (text.split("\n").some((line) => line.trim() !== "")) {
|
|
97
|
+
throw new Error(`Unable to recover channel seq from ${jsonlPath}`);
|
|
98
|
+
}
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Compute the next seq to assign by reconciling the `.seq` sidecar with
|
|
103
|
+
* the JSONL tail. Repairs the sidecar when it is missing, corrupted,
|
|
104
|
+
* lower than the JSONL tail, or ahead of the JSONL tail (for example,
|
|
105
|
+
* after manual corruption or a stale future reservation).
|
|
106
|
+
*
|
|
107
|
+
* Caller must hold the channel lock when invoking this and the
|
|
108
|
+
* subsequent JSONL append + sidecar write.
|
|
109
|
+
*/
|
|
110
|
+
export async function reconcileSeq(jsonlPath, sidecarPath) {
|
|
111
|
+
const sidecar = await readSidecar(sidecarPath);
|
|
112
|
+
const jsonlTail = await readLastJsonlSeq(jsonlPath);
|
|
113
|
+
// Decision matrix:
|
|
114
|
+
// sidecar = N, jsonl = N -> normal; next = N+1
|
|
115
|
+
// sidecar = N, jsonl = N+k -> sidecar stale; repair forward to N+k
|
|
116
|
+
// sidecar = N, jsonl = N-k -> sidecar ahead of JSONL;
|
|
117
|
+
// rewind to JSONL tail so we never
|
|
118
|
+
// leave a seq gap from a stale
|
|
119
|
+
// reservation
|
|
120
|
+
// sidecar = null, jsonl = M -> lazy rebuild; use jsonl tail
|
|
121
|
+
const last = jsonlTail;
|
|
122
|
+
if (sidecar !== last) {
|
|
123
|
+
await writeSidecar(sidecarPath, last);
|
|
124
|
+
}
|
|
125
|
+
return last;
|
|
126
|
+
}
|
|
127
|
+
export async function writeSidecar(sidecarPath, seq) {
|
|
128
|
+
await fsp.mkdir(path.dirname(sidecarPath), { recursive: true });
|
|
129
|
+
const tmp = `${sidecarPath}.tmp.${process.pid}.${Date.now()}`;
|
|
130
|
+
await fsp.writeFile(tmp, `${seq}\n`, "utf-8");
|
|
131
|
+
await fsp.rename(tmp, sidecarPath);
|
|
132
|
+
}
|
|
133
|
+
//# 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":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAG1E,MAAM,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAgD7C,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,CA6E7C"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { matchesEventFilter } from "./filter.js";
|
|
3
|
+
import { channelDir, eventsPath } from "./paths.js";
|
|
4
|
+
async function readNewEvents(filePath, state) {
|
|
5
|
+
if (!fs.existsSync(filePath)) {
|
|
6
|
+
state.byteOffset = 0;
|
|
7
|
+
state.carry = "";
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const stat = await fs.promises.stat(filePath);
|
|
11
|
+
if (stat.size < state.byteOffset) {
|
|
12
|
+
state.byteOffset = 0;
|
|
13
|
+
state.carry = "";
|
|
14
|
+
}
|
|
15
|
+
if (stat.size <= state.byteOffset)
|
|
16
|
+
return [];
|
|
17
|
+
const fh = await fs.promises.open(filePath, "r");
|
|
18
|
+
try {
|
|
19
|
+
const length = stat.size - state.byteOffset;
|
|
20
|
+
const buf = Buffer.alloc(length);
|
|
21
|
+
await fh.read(buf, 0, length, state.byteOffset);
|
|
22
|
+
state.byteOffset = stat.size;
|
|
23
|
+
const text = state.carry + buf.toString("utf-8");
|
|
24
|
+
const lines = text.split("\n");
|
|
25
|
+
state.carry = lines.pop() ?? "";
|
|
26
|
+
const events = [];
|
|
27
|
+
for (const line of lines) {
|
|
28
|
+
const t = line.trim();
|
|
29
|
+
if (!t)
|
|
30
|
+
continue;
|
|
31
|
+
try {
|
|
32
|
+
events.push(JSON.parse(t));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return events;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await fh.close();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function* watchEvents(channelName, filter, opts = {}) {
|
|
45
|
+
const file = eventsPath(channelName, opts.project);
|
|
46
|
+
if (!fs.existsSync(channelDir(channelName, opts.project))) {
|
|
47
|
+
await fs.promises.mkdir(channelDir(channelName, opts.project), {
|
|
48
|
+
recursive: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
let initialOffset = 0;
|
|
52
|
+
if (!opts.fromStart && opts.sinceSeq === undefined) {
|
|
53
|
+
try {
|
|
54
|
+
if (fs.existsSync(file)) {
|
|
55
|
+
initialOffset = (await fs.promises.stat(file)).size;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
initialOffset = 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const state = { byteOffset: initialOffset, carry: "" };
|
|
63
|
+
const sinceSeq = opts.sinceSeq;
|
|
64
|
+
let resolveNext = null;
|
|
65
|
+
const wake = () => {
|
|
66
|
+
if (resolveNext) {
|
|
67
|
+
const r = resolveNext;
|
|
68
|
+
resolveNext = null;
|
|
69
|
+
r();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
let watcher = null;
|
|
73
|
+
try {
|
|
74
|
+
watcher = fs.watch(channelDir(channelName, opts.project), () => wake());
|
|
75
|
+
watcher.on("error", () => {
|
|
76
|
+
try {
|
|
77
|
+
watcher?.close();
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// already closed
|
|
81
|
+
}
|
|
82
|
+
watcher = null;
|
|
83
|
+
// Keep the generator alive; the 200ms poll remains the fallback.
|
|
84
|
+
wake();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// ignore — fall back to polling
|
|
89
|
+
}
|
|
90
|
+
const poll = setInterval(wake, 200);
|
|
91
|
+
const abortHandler = () => wake();
|
|
92
|
+
opts.signal?.addEventListener("abort", abortHandler);
|
|
93
|
+
try {
|
|
94
|
+
while (true) {
|
|
95
|
+
if (opts.signal?.aborted)
|
|
96
|
+
return;
|
|
97
|
+
const fresh = await readNewEvents(file, state);
|
|
98
|
+
for (const ev of fresh) {
|
|
99
|
+
if (sinceSeq !== undefined && ev.seq <= sinceSeq)
|
|
100
|
+
continue;
|
|
101
|
+
if (matchesEventFilter(ev, filter))
|
|
102
|
+
yield ev;
|
|
103
|
+
if (opts.signal?.aborted)
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
await new Promise((resolve) => {
|
|
107
|
+
resolveNext = resolve;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
clearInterval(poll);
|
|
113
|
+
try {
|
|
114
|
+
watcher?.close();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// already closed
|
|
118
|
+
}
|
|
119
|
+
opts.signal?.removeEventListener("abort", abortHandler);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# 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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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ChannelEvent } from "./events.js";
|
|
2
|
+
import type { ChannelRef, InboxPolicy } from "./schema.js";
|
|
3
|
+
/**
|
|
4
|
+
* Process lifecycle of a worker, projected purely from durable channel
|
|
5
|
+
* events. Distinct from {@link WorkerActivity}, which tracks whether the
|
|
6
|
+
* worker is mid-turn.
|
|
7
|
+
*/
|
|
8
|
+
export type WorkerLifecycle = "starting" | "running" | "done" | "error" | "killed" | "crashed";
|
|
9
|
+
/** Turn activity of a worker — is it currently running a turn? */
|
|
10
|
+
export type WorkerActivity = "idle" | "mid-turn";
|
|
11
|
+
export interface WorkerState {
|
|
12
|
+
workerId: string;
|
|
13
|
+
/** Channel the worker belongs to. Stamped by the API layer. */
|
|
14
|
+
channel?: ChannelRef;
|
|
15
|
+
agent?: string;
|
|
16
|
+
provider?: string;
|
|
17
|
+
lifecycle: WorkerLifecycle;
|
|
18
|
+
terminal: boolean;
|
|
19
|
+
activity: WorkerActivity;
|
|
20
|
+
activeTurnId?: string;
|
|
21
|
+
activeTurnStartedAt?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Count of deliverable `message` events (matching the worker inbox
|
|
24
|
+
* policy) with seq greater than the latest consumed `turn_started.inputSeq`.
|
|
25
|
+
* Derived only from durable events — never from host-local cursors.
|
|
26
|
+
* Always 0 for terminal workers.
|
|
27
|
+
*/
|
|
28
|
+
pendingMessageCount: number;
|
|
29
|
+
inboxPolicy: InboxPolicy;
|
|
30
|
+
spawnedAt?: string;
|
|
31
|
+
updatedAt: string;
|
|
32
|
+
startedBy?: string;
|
|
33
|
+
exitCode?: number;
|
|
34
|
+
signal?: string;
|
|
35
|
+
reason?: string;
|
|
36
|
+
error?: string;
|
|
37
|
+
/** Seq of the last event applied to this worker. */
|
|
38
|
+
lastSeq: number;
|
|
39
|
+
}
|
|
40
|
+
export interface WorkerRegistry {
|
|
41
|
+
workers: WorkerState[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Project durable channel events into the worker registry. Pure — only
|
|
45
|
+
* the event log feeds the projection (no pid files, no inbox cursors).
|
|
46
|
+
*/
|
|
47
|
+
export declare function reduceWorkerRegistry(events: ChannelEvent[], channel?: ChannelRef): WorkerRegistry;
|
|
48
|
+
export declare function isTerminalLifecycle(lifecycle: WorkerLifecycle): boolean;
|
|
49
|
+
//# sourceMappingURL=worker-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-state.d.ts","sourceRoot":"","sources":["../../../../src/channel/internal/store/worker-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,SAAS,GACT,MAAM,GACN,OAAO,GACP,QAAQ,GACR,SAAS,CAAC;AAEd,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AASjD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AA4ED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,EAAE,EACtB,OAAO,CAAC,EAAE,UAAU,GACnB,cAAc,CA+HhB;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAEvE"}
|