@chances-ai/ui-core 24.2.0 → 25.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/editor/buffer.d.ts +57 -0
  2. package/dist/editor/buffer.d.ts.map +1 -0
  3. package/dist/editor/buffer.js +189 -0
  4. package/dist/editor/buffer.js.map +1 -0
  5. package/dist/editor/completion.d.ts +25 -0
  6. package/dist/editor/completion.d.ts.map +1 -0
  7. package/dist/editor/completion.js +27 -0
  8. package/dist/editor/completion.js.map +1 -0
  9. package/dist/editor/component.d.ts +58 -0
  10. package/dist/editor/component.d.ts.map +1 -0
  11. package/dist/editor/component.js +125 -0
  12. package/dist/editor/component.js.map +1 -0
  13. package/dist/editor/index.d.ts +15 -0
  14. package/dist/editor/index.d.ts.map +1 -0
  15. package/dist/editor/index.js +15 -0
  16. package/dist/editor/index.js.map +1 -0
  17. package/dist/editor/input-mode.d.ts +26 -0
  18. package/dist/editor/input-mode.d.ts.map +1 -0
  19. package/dist/editor/input-mode.js +17 -0
  20. package/dist/editor/input-mode.js.map +1 -0
  21. package/dist/editor/kill-ring.d.ts +36 -0
  22. package/dist/editor/kill-ring.d.ts.map +1 -0
  23. package/dist/editor/kill-ring.js +58 -0
  24. package/dist/editor/kill-ring.js.map +1 -0
  25. package/dist/editor/layout.d.ts +60 -0
  26. package/dist/editor/layout.d.ts.map +1 -0
  27. package/dist/editor/layout.js +113 -0
  28. package/dist/editor/layout.js.map +1 -0
  29. package/dist/editor/reducer.d.ts +93 -0
  30. package/dist/editor/reducer.d.ts.map +1 -0
  31. package/dist/editor/reducer.js +196 -0
  32. package/dist/editor/reducer.js.map +1 -0
  33. package/dist/editor/segments.d.ts +46 -0
  34. package/dist/editor/segments.d.ts.map +1 -0
  35. package/dist/editor/segments.js +104 -0
  36. package/dist/editor/segments.js.map +1 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +5 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/session-summary.d.ts +18 -0
  42. package/dist/session-summary.d.ts.map +1 -0
  43. package/dist/session-summary.js +2 -0
  44. package/dist/session-summary.js.map +1 -0
  45. package/dist/view-model.d.ts +4 -0
  46. package/dist/view-model.d.ts.map +1 -1
  47. package/dist/view-model.js +10 -0
  48. package/dist/view-model.js.map +1 -1
  49. package/package.json +5 -4
@@ -0,0 +1,57 @@
1
+ /**
2
+ * (7.4 / task 04) `TextBuffer` = the editor's minimal state `{ text, cursor }`
3
+ * (cursor = a UTF-16 offset, always grapheme-aligned) + the PURE cursor/edit
4
+ * functions over it (docs/7.4 §2.3). All operations return a NEW buffer; delete
5
+ * variants additionally return the killed text + direction (fed to the kill-ring
6
+ * by the reducer). No Ink/React/node — unit-tested without a TTY.
7
+ */
8
+ export interface TextBuffer {
9
+ /** NFC-normalized draft text. */
10
+ readonly text: string;
11
+ /** Cursor offset (UTF-16), 0..=text.length, grapheme-aligned. */
12
+ readonly cursor: number;
13
+ }
14
+ /** A delete that feeds the kill-ring: the resulting buffer + what was removed. */
15
+ export interface KillResult {
16
+ buffer: TextBuffer;
17
+ killed: string;
18
+ dir: "backward" | "forward";
19
+ }
20
+ /** Build a buffer; `text` is NFC-normalized, `cursor` defaults to end + clamps. */
21
+ export declare function makeBuffer(text?: string, cursor?: number): TextBuffer;
22
+ /** Insert `s` (NFC) at the cursor; cursor advances past it. */
23
+ export declare function insert(buf: TextBuffer, s: string): TextBuffer;
24
+ /** Delete the grapheme before the cursor (plain backspace — NOT a kill). */
25
+ export declare function backspace(buf: TextBuffer): TextBuffer;
26
+ /** Delete the grapheme after the cursor (plain forward-delete — NOT a kill). */
27
+ export declare function deleteForward(buf: TextBuffer): TextBuffer;
28
+ export declare function moveLeft(buf: TextBuffer): TextBuffer;
29
+ export declare function moveRight(buf: TextBuffer): TextBuffer;
30
+ /**
31
+ * Move left by one "word" (oh-my-pi `moveWordLeft`): skip trailing whitespace,
32
+ * then consume a run of the kind under the cursor — `word` consumes a letter/
33
+ * digit run incl. internal joiners (`foo-bar`); `delimiter` consumes a delimiter
34
+ * run; `cjk`/`other` move ONE cluster (CJK is per-char, docs/7.4 §2.3).
35
+ */
36
+ export declare function moveWordLeft(buf: TextBuffer): TextBuffer;
37
+ /** Mirror of {@link moveWordLeft}, rightward. */
38
+ export declare function moveWordRight(buf: TextBuffer): TextBuffer;
39
+ /** Start offset of the logical line (`\n`-delimited) containing `offset`. */
40
+ export declare function lineStartOffset(text: string, offset: number): number;
41
+ /** End offset of the logical line containing `offset` (the `\n`, or text end). */
42
+ export declare function lineEndOffset(text: string, offset: number): number;
43
+ export declare function moveLineStart(buf: TextBuffer): TextBuffer;
44
+ export declare function moveLineEnd(buf: TextBuffer): TextBuffer;
45
+ export declare function moveBufferStart(buf: TextBuffer): TextBuffer;
46
+ export declare function moveBufferEnd(buf: TextBuffer): TextBuffer;
47
+ /** Set the cursor to an explicit offset (used by visual up/down). Clamped. */
48
+ export declare function setCursor(buf: TextBuffer, cursor: number): TextBuffer;
49
+ /** Ctrl-W / Meta-Backspace: kill the word before the cursor. */
50
+ export declare function deleteWordBackward(buf: TextBuffer): KillResult;
51
+ /** Meta-D: kill the word after the cursor. */
52
+ export declare function deleteWordForward(buf: TextBuffer): KillResult;
53
+ /** Ctrl-K: kill to end of line; at line end kill the newline (join next line). */
54
+ export declare function killToLineEnd(buf: TextBuffer): KillResult;
55
+ /** Ctrl-U: kill from line start to the cursor. */
56
+ export declare function killToLineStart(buf: TextBuffer): KillResult;
57
+ //# sourceMappingURL=buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/editor/buffer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,UAAU,GAAG,SAAS,CAAC;CAC7B;AAMD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAGjE;AAQD,+DAA+D;AAC/D,wBAAgB,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,CAG7D;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAIrD;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAIzD;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAEpD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAmCxD;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAoCzD;AAID,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGlE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAEzD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAEvD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAE3D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAEzD;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAErE;AAID,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAI9D;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAI7D;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAKzD;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAI3D"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * (7.4 / task 04) `TextBuffer` = the editor's minimal state `{ text, cursor }`
3
+ * (cursor = a UTF-16 offset, always grapheme-aligned) + the PURE cursor/edit
4
+ * functions over it (docs/7.4 §2.3). All operations return a NEW buffer; delete
5
+ * variants additionally return the killed text + direction (fed to the kill-ring
6
+ * by the reducer). No Ink/React/node — unit-tested without a TTY.
7
+ */
8
+ import { graphemeBoundaries, getWordNavKind, isWordJoiner, nextGraphemeOffset, prevGraphemeOffset, toNFC, } from "./segments.js";
9
+ function clamp(n, lo, hi) {
10
+ return Math.max(lo, Math.min(hi, n));
11
+ }
12
+ /** Build a buffer; `text` is NFC-normalized, `cursor` defaults to end + clamps. */
13
+ export function makeBuffer(text = "", cursor) {
14
+ const t = toNFC(text);
15
+ return { text: t, cursor: cursor === undefined ? t.length : clamp(cursor, 0, t.length) };
16
+ }
17
+ function splice(text, start, end, insert) {
18
+ return text.slice(0, start) + insert + text.slice(end);
19
+ }
20
+ // -- editing --
21
+ /** Insert `s` (NFC) at the cursor; cursor advances past it. */
22
+ export function insert(buf, s) {
23
+ const ins = toNFC(s);
24
+ return { text: splice(buf.text, buf.cursor, buf.cursor, ins), cursor: buf.cursor + ins.length };
25
+ }
26
+ /** Delete the grapheme before the cursor (plain backspace — NOT a kill). */
27
+ export function backspace(buf) {
28
+ if (buf.cursor === 0)
29
+ return buf;
30
+ const prev = prevGraphemeOffset(buf.text, buf.cursor);
31
+ return { text: splice(buf.text, prev, buf.cursor, ""), cursor: prev };
32
+ }
33
+ /** Delete the grapheme after the cursor (plain forward-delete — NOT a kill). */
34
+ export function deleteForward(buf) {
35
+ if (buf.cursor >= buf.text.length)
36
+ return buf;
37
+ const next = nextGraphemeOffset(buf.text, buf.cursor);
38
+ return { text: splice(buf.text, buf.cursor, next, ""), cursor: buf.cursor };
39
+ }
40
+ // -- horizontal movement --
41
+ export function moveLeft(buf) {
42
+ return buf.cursor === 0 ? buf : { ...buf, cursor: prevGraphemeOffset(buf.text, buf.cursor) };
43
+ }
44
+ export function moveRight(buf) {
45
+ return buf.cursor >= buf.text.length ? buf : { ...buf, cursor: nextGraphemeOffset(buf.text, buf.cursor) };
46
+ }
47
+ /**
48
+ * Move left by one "word" (oh-my-pi `moveWordLeft`): skip trailing whitespace,
49
+ * then consume a run of the kind under the cursor — `word` consumes a letter/
50
+ * digit run incl. internal joiners (`foo-bar`); `delimiter` consumes a delimiter
51
+ * run; `cjk`/`other` move ONE cluster (CJK is per-char, docs/7.4 §2.3).
52
+ */
53
+ export function moveWordLeft(buf) {
54
+ const { text } = buf;
55
+ if (buf.cursor === 0)
56
+ return buf;
57
+ const b = graphemeBoundaries(text);
58
+ let k = b.indexOf(buf.cursor);
59
+ if (k < 0)
60
+ return { ...buf, cursor: prevGraphemeOffset(text, buf.cursor) };
61
+ const left = () => (k > 0 ? text.slice(b[k - 1], b[k]) : "");
62
+ const leftLeft = () => (k > 1 ? text.slice(b[k - 2], b[k - 1]) : "");
63
+ while (k > 0 && getWordNavKind(left()) === "whitespace")
64
+ k--;
65
+ if (k === 0)
66
+ return { ...buf, cursor: 0 };
67
+ const kind = getWordNavKind(left());
68
+ if (kind === "delimiter") {
69
+ while (k > 0 && getWordNavKind(left()) === "delimiter")
70
+ k--;
71
+ }
72
+ else if (kind === "word") {
73
+ let hasWord = false;
74
+ while (k > 0) {
75
+ const g = left();
76
+ const gk = getWordNavKind(g);
77
+ if (gk === "word") {
78
+ hasWord = true;
79
+ k--;
80
+ continue;
81
+ }
82
+ if (hasWord && gk === "delimiter" && isWordJoiner(g) && getWordNavKind(leftLeft()) === "word") {
83
+ k--;
84
+ continue;
85
+ }
86
+ break;
87
+ }
88
+ }
89
+ else {
90
+ k--; // cjk / other → single cluster
91
+ }
92
+ return { ...buf, cursor: b[k] };
93
+ }
94
+ /** Mirror of {@link moveWordLeft}, rightward. */
95
+ export function moveWordRight(buf) {
96
+ const { text } = buf;
97
+ if (buf.cursor >= text.length)
98
+ return buf;
99
+ const b = graphemeBoundaries(text);
100
+ let k = b.indexOf(buf.cursor);
101
+ if (k < 0)
102
+ return { ...buf, cursor: nextGraphemeOffset(text, buf.cursor) };
103
+ const last = b.length - 1;
104
+ const right = () => (k < last ? text.slice(b[k], b[k + 1]) : "");
105
+ const rightRight = () => (k + 1 < last ? text.slice(b[k + 1], b[k + 2]) : "");
106
+ while (k < last && getWordNavKind(right()) === "whitespace")
107
+ k++;
108
+ if (k === last)
109
+ return { ...buf, cursor: text.length };
110
+ const kind = getWordNavKind(right());
111
+ if (kind === "delimiter") {
112
+ while (k < last && getWordNavKind(right()) === "delimiter")
113
+ k++;
114
+ }
115
+ else if (kind === "word") {
116
+ let hasWord = false;
117
+ while (k < last) {
118
+ const g = right();
119
+ const gk = getWordNavKind(g);
120
+ if (gk === "word") {
121
+ hasWord = true;
122
+ k++;
123
+ continue;
124
+ }
125
+ if (hasWord && gk === "delimiter" && isWordJoiner(g) && getWordNavKind(rightRight()) === "word") {
126
+ k++;
127
+ continue;
128
+ }
129
+ break;
130
+ }
131
+ }
132
+ else {
133
+ k++;
134
+ }
135
+ return { ...buf, cursor: b[k] };
136
+ }
137
+ // -- logical-line + buffer bounds --
138
+ /** Start offset of the logical line (`\n`-delimited) containing `offset`. */
139
+ export function lineStartOffset(text, offset) {
140
+ return text.lastIndexOf("\n", offset - 1) + 1;
141
+ }
142
+ /** End offset of the logical line containing `offset` (the `\n`, or text end). */
143
+ export function lineEndOffset(text, offset) {
144
+ const nl = text.indexOf("\n", offset);
145
+ return nl < 0 ? text.length : nl;
146
+ }
147
+ export function moveLineStart(buf) {
148
+ return { ...buf, cursor: lineStartOffset(buf.text, buf.cursor) };
149
+ }
150
+ export function moveLineEnd(buf) {
151
+ return { ...buf, cursor: lineEndOffset(buf.text, buf.cursor) };
152
+ }
153
+ export function moveBufferStart(buf) {
154
+ return { ...buf, cursor: 0 };
155
+ }
156
+ export function moveBufferEnd(buf) {
157
+ return { ...buf, cursor: buf.text.length };
158
+ }
159
+ /** Set the cursor to an explicit offset (used by visual up/down). Clamped. */
160
+ export function setCursor(buf, cursor) {
161
+ return { ...buf, cursor: clamp(cursor, 0, buf.text.length) };
162
+ }
163
+ // -- kills (feed the kill-ring) --
164
+ /** Ctrl-W / Meta-Backspace: kill the word before the cursor. */
165
+ export function deleteWordBackward(buf) {
166
+ const target = moveWordLeft(buf).cursor;
167
+ const killed = buf.text.slice(target, buf.cursor);
168
+ return { buffer: { text: splice(buf.text, target, buf.cursor, ""), cursor: target }, killed, dir: "backward" };
169
+ }
170
+ /** Meta-D: kill the word after the cursor. */
171
+ export function deleteWordForward(buf) {
172
+ const target = moveWordRight(buf).cursor;
173
+ const killed = buf.text.slice(buf.cursor, target);
174
+ return { buffer: { text: splice(buf.text, buf.cursor, target, ""), cursor: buf.cursor }, killed, dir: "forward" };
175
+ }
176
+ /** Ctrl-K: kill to end of line; at line end kill the newline (join next line). */
177
+ export function killToLineEnd(buf) {
178
+ const lineEnd = lineEndOffset(buf.text, buf.cursor);
179
+ const end = buf.cursor === lineEnd && lineEnd < buf.text.length ? lineEnd + 1 : lineEnd;
180
+ const killed = buf.text.slice(buf.cursor, end);
181
+ return { buffer: { text: splice(buf.text, buf.cursor, end, ""), cursor: buf.cursor }, killed, dir: "forward" };
182
+ }
183
+ /** Ctrl-U: kill from line start to the cursor. */
184
+ export function killToLineStart(buf) {
185
+ const start = lineStartOffset(buf.text, buf.cursor);
186
+ const killed = buf.text.slice(start, buf.cursor);
187
+ return { buffer: { text: splice(buf.text, start, buf.cursor, ""), cursor: start }, killed, dir: "backward" };
188
+ }
189
+ //# sourceMappingURL=buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../src/editor/buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * (7.4 / task 04 W5) Pure detection of the autocomplete trigger under the draft
3
+ * (docs/7.4 §6.1). Browser-safe; the TUI gathers candidates + ranks via the
4
+ * native fuzzy ranker, this just classifies the trailing token. Operates on the
5
+ * cursor-at-end case (the common one — matches the existing typeahead).
6
+ */
7
+ export type CompletionKind = "slash" | "mention";
8
+ export interface CompletionTrigger {
9
+ kind: CompletionKind;
10
+ /** Text after the leading `/` or `@`. */
11
+ query: string;
12
+ /** Offset where the trigger token (`/` or `@`) begins. */
13
+ start: number;
14
+ }
15
+ /**
16
+ * Classify the trailing token of `text`:
17
+ * - `slash` — the whole draft is `/word` (a command-NAME segment: starts with
18
+ * `/`, no whitespace yet). Once a space is typed the menu hides and Enter
19
+ * submits the full line.
20
+ * - `mention` — the trailing token starts with `@` (preceded by start-of-line
21
+ * or whitespace), e.g. `@src/fo`, `@agent`, `@server:uri`.
22
+ * Returns null when nothing is being completed.
23
+ */
24
+ export declare function detectCompletion(text: string): CompletionTrigger | null;
25
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/editor/completion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAUvE"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * (7.4 / task 04 W5) Pure detection of the autocomplete trigger under the draft
3
+ * (docs/7.4 §6.1). Browser-safe; the TUI gathers candidates + ranks via the
4
+ * native fuzzy ranker, this just classifies the trailing token. Operates on the
5
+ * cursor-at-end case (the common one — matches the existing typeahead).
6
+ */
7
+ /**
8
+ * Classify the trailing token of `text`:
9
+ * - `slash` — the whole draft is `/word` (a command-NAME segment: starts with
10
+ * `/`, no whitespace yet). Once a space is typed the menu hides and Enter
11
+ * submits the full line.
12
+ * - `mention` — the trailing token starts with `@` (preceded by start-of-line
13
+ * or whitespace), e.g. `@src/fo`, `@agent`, `@server:uri`.
14
+ * Returns null when nothing is being completed.
15
+ */
16
+ export function detectCompletion(text) {
17
+ if (text.startsWith("/") && !/\s/.test(text)) {
18
+ return { kind: "slash", query: text.slice(1), start: 0 };
19
+ }
20
+ const m = /(?:^|\s)@(\S*)$/.exec(text);
21
+ if (m) {
22
+ const query = m[1] ?? "";
23
+ return { kind: "mention", query, start: text.length - query.length - 1 };
24
+ }
25
+ return null;
26
+ }
27
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../../src/editor/completion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAC3D,CAAC;IACD,MAAM,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * (7.4 / task 04) The `EditorComponent` seam (docs/7.4 §2.8, R1-M4): a single
3
+ * RAW entry point `handle(EditorInput)` so a vim editor can drop in later. The
4
+ * default `EmacsEditor` owns a `token → EditorAction` keymap (= keybindings.json
5
+ * `Editor` context merged over the Emacs defaults — fully rebindable) + the pure
6
+ * `editorReducer`; the upper TUI layer forwards canonical key tokens + paste and
7
+ * never pre-resolves actions. PURE (measure injected) — no Ink/React/node.
8
+ */
9
+ import { type MeasureFn } from "./segments.js";
10
+ import { type EditorAction, type EditorState } from "./reducer.js";
11
+ /** One raw input event for the editor. `key` carries a canonical token (from
12
+ * ink-ext `keyToken`) + the raw char; `paste` carries a bracketed-paste body. */
13
+ export type EditorInput = {
14
+ kind: "key";
15
+ token: string;
16
+ char: string;
17
+ } | {
18
+ kind: "paste";
19
+ text: string;
20
+ };
21
+ /** Side-effect the host must act on after `handle`. `historyPrev/Next` fire when
22
+ * a ↑/↓ couldn't move the cursor (already at top/bottom) → fall back to history. */
23
+ export interface EditorEffect {
24
+ kind: "submit" | "newline" | "none" | "historyPrev" | "historyNext";
25
+ }
26
+ export interface EditorComponent {
27
+ getState(): EditorState;
28
+ getText(): string;
29
+ setText(text: string): void;
30
+ /** Current wrap width (terminal columns) for visual ↑/↓ + layout. */
31
+ setWidth(width: number): void;
32
+ handle(ev: EditorInput): EditorEffect;
33
+ }
34
+ /** token → editor action. Bare action names (no `editor:` prefix) = `EditorAction["t"]`. */
35
+ export type EditorKeymap = ReadonlyMap<string, EditorAction["t"]>;
36
+ /** The default Emacs keymap (docs/7.4 §4.2). `up`/`down`/`return`/`shift+return`/
37
+ * `meta+return` are handled specially in {@link EmacsEditor.handle}, not here. */
38
+ export declare function defaultEditorKeymap(): Map<string, EditorAction["t"]>;
39
+ export declare class EmacsEditor implements EditorComponent {
40
+ private state;
41
+ private readonly keymap;
42
+ private readonly measure;
43
+ private width;
44
+ private preferredCol;
45
+ constructor(opts?: {
46
+ text?: string;
47
+ keymap?: EditorKeymap;
48
+ measure?: MeasureFn;
49
+ width?: number;
50
+ });
51
+ getState(): EditorState;
52
+ getText(): string;
53
+ setText(text: string): void;
54
+ setWidth(width: number): void;
55
+ private dispatch;
56
+ handle(ev: EditorInput): EditorEffect;
57
+ }
58
+ //# sourceMappingURL=component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/editor/component.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAGjB,MAAM,cAAc,CAAC;AAEtB;kFACkF;AAClF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC;qFACqF;AACrF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC;CACrE;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,IAAI,WAAW,CAAC;IACxB,OAAO,IAAI,MAAM,CAAC;IAClB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,EAAE,WAAW,GAAG,YAAY,CAAC;CACvC;AAED,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;AAElE;mFACmF;AACnF,wBAAgB,mBAAmB,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAwBpE;AAWD,qBAAa,WAAY,YAAW,eAAe;IACjD,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAuB;gBAE/B,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,YAAY,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;IAOpG,QAAQ,IAAI,WAAW;IAIvB,OAAO,IAAI,MAAM;IAIjB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,OAAO,CAAC,QAAQ;IAMhB,MAAM,CAAC,EAAE,EAAE,WAAW,GAAG,YAAY;CA6CtC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * (7.4 / task 04) The `EditorComponent` seam (docs/7.4 §2.8, R1-M4): a single
3
+ * RAW entry point `handle(EditorInput)` so a vim editor can drop in later. The
4
+ * default `EmacsEditor` owns a `token → EditorAction` keymap (= keybindings.json
5
+ * `Editor` context merged over the Emacs defaults — fully rebindable) + the pure
6
+ * `editorReducer`; the upper TUI layer forwards canonical key tokens + paste and
7
+ * never pre-resolves actions. PURE (measure injected) — no Ink/React/node.
8
+ */
9
+ import { decideEnter } from "./input-mode.js";
10
+ import { graphemeWidth } from "./segments.js";
11
+ import { moveVisual } from "./layout.js";
12
+ import { editorReducer, initialEditorState, } from "./reducer.js";
13
+ /** The default Emacs keymap (docs/7.4 §4.2). `up`/`down`/`return`/`shift+return`/
14
+ * `meta+return` are handled specially in {@link EmacsEditor.handle}, not here. */
15
+ export function defaultEditorKeymap() {
16
+ return new Map([
17
+ ["ctrl+a", "moveLineStart"],
18
+ ["ctrl+e", "moveLineEnd"],
19
+ ["ctrl+b", "moveLeft"],
20
+ ["left", "moveLeft"],
21
+ ["ctrl+f", "moveRight"],
22
+ ["right", "moveRight"],
23
+ ["meta+b", "moveWordLeft"],
24
+ ["meta+f", "moveWordRight"],
25
+ ["ctrl+w", "deleteWordBackward"],
26
+ ["meta+backspace", "deleteWordBackward"],
27
+ ["ctrl+backspace", "deleteWordBackward"],
28
+ ["meta+d", "deleteWordForward"],
29
+ ["ctrl+k", "killToLineEnd"],
30
+ ["ctrl+u", "killToLineStart"],
31
+ ["ctrl+y", "yank"],
32
+ ["meta+y", "yankPop"],
33
+ ["ctrl+d", "deleteForward"],
34
+ ["delete", "deleteForward"],
35
+ ["backspace", "backspace"],
36
+ ["ctrl+h", "backspace"],
37
+ ["ctrl+_", "undo"],
38
+ ]);
39
+ }
40
+ /** A printable single key (token equals its own char, no modifier prefix). */
41
+ function isPrintable(token, char) {
42
+ if (token !== char || char === "")
43
+ return false;
44
+ for (const c of char) {
45
+ if (c < " " || c === "\x7f")
46
+ return false;
47
+ }
48
+ return true;
49
+ }
50
+ export class EmacsEditor {
51
+ state;
52
+ keymap;
53
+ measure;
54
+ width;
55
+ preferredCol = null;
56
+ constructor(opts = {}) {
57
+ this.state = initialEditorState(opts.text ?? "");
58
+ this.keymap = opts.keymap ?? defaultEditorKeymap();
59
+ this.measure = opts.measure ?? graphemeWidth;
60
+ this.width = opts.width ?? 80;
61
+ }
62
+ getState() {
63
+ return this.state;
64
+ }
65
+ getText() {
66
+ return this.state.buffer.text;
67
+ }
68
+ setText(text) {
69
+ this.state = editorReducer(this.state, { t: "setText", text });
70
+ this.preferredCol = null;
71
+ }
72
+ setWidth(width) {
73
+ this.width = Math.max(1, width);
74
+ }
75
+ dispatch(action) {
76
+ this.state = editorReducer(this.state, action);
77
+ // A vertical move keeps the sticky column; everything else resets it.
78
+ if (action.t !== "setCursor")
79
+ this.preferredCol = null;
80
+ }
81
+ handle(ev) {
82
+ if (ev.kind === "paste") {
83
+ this.dispatch({ t: "insert", text: ev.text });
84
+ return { kind: "none" };
85
+ }
86
+ const { token, char } = ev;
87
+ if (token === "return") {
88
+ const buffer = this.state.buffer;
89
+ if (decideEnter(buffer) === "backslash-continuation") {
90
+ this.dispatch({ t: "backspace" }); // drop the trailing `\`
91
+ this.dispatch({ t: "newline" });
92
+ return { kind: "newline" };
93
+ }
94
+ return { kind: "submit" };
95
+ }
96
+ if (token === "shift+return" || token === "meta+return") {
97
+ this.dispatch({ t: "newline" });
98
+ return { kind: "newline" };
99
+ }
100
+ if (token === "up" || token === "down") {
101
+ const dir = token === "up" ? -1 : 1;
102
+ const mv = moveVisual(this.state.buffer, this.width, dir, this.preferredCol, this.measure);
103
+ if (!mv.moved)
104
+ return { kind: dir < 0 ? "historyPrev" : "historyNext" };
105
+ this.state = editorReducer(this.state, { t: "setCursor", cursor: mv.cursor });
106
+ this.preferredCol = mv.preferredCol;
107
+ return { kind: "none" };
108
+ }
109
+ if (token === "space") {
110
+ this.dispatch({ t: "insert", text: " " });
111
+ return { kind: "none" };
112
+ }
113
+ const action = this.keymap.get(token);
114
+ if (action) {
115
+ this.dispatch({ t: action });
116
+ return { kind: "none" };
117
+ }
118
+ if (isPrintable(token, char)) {
119
+ this.dispatch({ t: "insert", text: char });
120
+ return { kind: "none" };
121
+ }
122
+ return { kind: "none" };
123
+ }
124
+ }
125
+ //# sourceMappingURL=component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/editor/component.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * (7.4 / task 04) `@chances-ai/ui-core` editor core — the surface-agnostic,
3
+ * browser-safe, PURE editing model (cursor/word/kill-ring/undo/layout + `!`
4
+ * parse + Enter decision + the `EditorComponent` vim-ready seam). Re-exported
5
+ * from `ui-core/index.ts`. See docs/7.4 §2.
6
+ */
7
+ export { toNFC, graphemeSegments, graphemeBoundaries, nextGraphemeOffset, prevGraphemeOffset, graphemeWidth, widthOf, getWordNavKind, isWordJoiner, type MeasureFn, type WordNavKind, } from "./segments.js";
8
+ export { type TextBuffer, type KillResult, makeBuffer, insert, backspace, deleteForward, moveLeft, moveRight, moveWordLeft, moveWordRight, moveLineStart, moveLineEnd, moveBufferStart, moveBufferEnd, setCursor, lineStartOffset, lineEndOffset, deleteWordBackward, deleteWordForward, killToLineEnd, killToLineStart, } from "./buffer.js";
9
+ export { KillRing } from "./kill-ring.js";
10
+ export { type EditorState, type EditorAction, type LastAction, type Snapshot, editorReducer, initialEditorState, EDITOR_ACTION_TYPES, BINDABLE_EDITOR_ACTIONS, } from "./reducer.js";
11
+ export { type VisualRow, type Layout, type VisualMove, type Viewport, layout, moveVisual, viewportRows, } from "./layout.js";
12
+ export { type InputMode, type EnterDecision, parseInputMode, decideEnter } from "./input-mode.js";
13
+ export { type CompletionKind, type CompletionTrigger, detectCompletion } from "./completion.js";
14
+ export { type EditorInput, type EditorEffect, type EditorComponent, type EditorKeymap, EmacsEditor, defaultEditorKeymap, } from "./component.js";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/editor/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,OAAO,EACP,cAAc,EACd,YAAY,EACZ,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,UAAU,EACV,MAAM,EACN,SAAS,EACT,aAAa,EACb,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,aAAa,EACb,SAAS,EACT,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,MAAM,EACN,UAAU,EACV,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAElG,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEhG,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,WAAW,EACX,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * (7.4 / task 04) `@chances-ai/ui-core` editor core — the surface-agnostic,
3
+ * browser-safe, PURE editing model (cursor/word/kill-ring/undo/layout + `!`
4
+ * parse + Enter decision + the `EditorComponent` vim-ready seam). Re-exported
5
+ * from `ui-core/index.ts`. See docs/7.4 §2.
6
+ */
7
+ export { toNFC, graphemeSegments, graphemeBoundaries, nextGraphemeOffset, prevGraphemeOffset, graphemeWidth, widthOf, getWordNavKind, isWordJoiner, } from "./segments.js";
8
+ export { makeBuffer, insert, backspace, deleteForward, moveLeft, moveRight, moveWordLeft, moveWordRight, moveLineStart, moveLineEnd, moveBufferStart, moveBufferEnd, setCursor, lineStartOffset, lineEndOffset, deleteWordBackward, deleteWordForward, killToLineEnd, killToLineStart, } from "./buffer.js";
9
+ export { KillRing } from "./kill-ring.js";
10
+ export { editorReducer, initialEditorState, EDITOR_ACTION_TYPES, BINDABLE_EDITOR_ACTIONS, } from "./reducer.js";
11
+ export { layout, moveVisual, viewportRows, } from "./layout.js";
12
+ export { parseInputMode, decideEnter } from "./input-mode.js";
13
+ export { detectCompletion } from "./completion.js";
14
+ export { EmacsEditor, defaultEditorKeymap, } from "./component.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/editor/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,OAAO,EACP,cAAc,EACd,YAAY,GAGb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAGL,UAAU,EACV,MAAM,EACN,SAAS,EACT,aAAa,EACb,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,aAAa,EACb,SAAS,EACT,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAKL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAKL,MAAM,EACN,UAAU,EACV,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAsC,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAElG,OAAO,EAA+C,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEhG,OAAO,EAKL,WAAW,EACX,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * (7.4 / task 04) `!` input-mode parse + Enter decision — defined ONCE here so
3
+ * TUI / web / KMP share one rule (docs/7.4 §2.7, decisions `[12.6][12.7]`). PURE.
4
+ */
5
+ import type { TextBuffer } from "./buffer.js";
6
+ export type InputMode = "prompt" | "bash";
7
+ /** Split a draft into `{ mode, value }`. A leading `!` is the bash prefix; the
8
+ * returned `value` has the `!` (and following whitespace) stripped. */
9
+ export declare function parseInputMode(text: string): {
10
+ mode: InputMode;
11
+ value: string;
12
+ };
13
+ /**
14
+ * What a plain Enter does (docs/7.4 §2.7, R1-S2 — matches claude-code's real
15
+ * behaviour):
16
+ * - `backslash-continuation` — a trailing `\` immediately before the cursor →
17
+ * drop the `\` and insert a newline (shell-style line continuation; the most
18
+ * reliable cross-terminal multiline entry).
19
+ * - `submit` — otherwise.
20
+ *
21
+ * `Shift+Enter` / `Meta+Enter` map straight to a newline upstream (token-based,
22
+ * not via this fn); paste keeps its own newlines (never reaches here).
23
+ */
24
+ export type EnterDecision = "submit" | "backslash-continuation";
25
+ export declare function decideEnter(buffer: TextBuffer): EnterDecision;
26
+ //# sourceMappingURL=input-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-mode.d.ts","sourceRoot":"","sources":["../../src/editor/input-mode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1C;wEACwE;AACxE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAG/E;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,wBAAwB,CAAC;AAEhE,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAG7D"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * (7.4 / task 04) `!` input-mode parse + Enter decision — defined ONCE here so
3
+ * TUI / web / KMP share one rule (docs/7.4 §2.7, decisions `[12.6][12.7]`). PURE.
4
+ */
5
+ /** Split a draft into `{ mode, value }`. A leading `!` is the bash prefix; the
6
+ * returned `value` has the `!` (and following whitespace) stripped. */
7
+ export function parseInputMode(text) {
8
+ if (text.startsWith("!"))
9
+ return { mode: "bash", value: text.slice(1).replace(/^\s+/, "") };
10
+ return { mode: "prompt", value: text };
11
+ }
12
+ export function decideEnter(buffer) {
13
+ if (buffer.cursor > 0 && buffer.text[buffer.cursor - 1] === "\\")
14
+ return "backslash-continuation";
15
+ return "submit";
16
+ }
17
+ //# sourceMappingURL=input-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-mode.js","sourceRoot":"","sources":["../../src/editor/input-mode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;wEACwE;AACxE,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;IAC5F,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAeD,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,wBAAwB,CAAC;IAClG,OAAO,QAAQ,CAAC;AAClB,CAAC"}