@larose/pi-web 0.3.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 (43) hide show
  1. package/LICENSE +235 -0
  2. package/README.md +50 -0
  3. package/THIRD_PARTY_LICENSES.md +40 -0
  4. package/dist/client/home.js +1619 -0
  5. package/dist/client/session.js +3703 -0
  6. package/dist/server/api.js +485 -0
  7. package/dist/server/cli.js +51 -0
  8. package/dist/server/directory-browser.js +104 -0
  9. package/dist/server/errors.js +10 -0
  10. package/dist/server/event-buffer.js +40 -0
  11. package/dist/server/extension-ui.js +245 -0
  12. package/dist/server/git-workspaces.js +559 -0
  13. package/dist/server/runtime-registry.js +703 -0
  14. package/dist/server/server.js +190 -0
  15. package/dist/server/session-repository.js +374 -0
  16. package/package.json +46 -0
  17. package/public/home.html +139 -0
  18. package/public/session.html +144 -0
  19. package/public/styles.css +2463 -0
  20. package/screenshots/home.png +0 -0
  21. package/screenshots/session.png +0 -0
  22. package/src/client/display-title.ts +36 -0
  23. package/src/client/event-stream.ts +194 -0
  24. package/src/client/home.ts +1575 -0
  25. package/src/client/markdown.ts +98 -0
  26. package/src/client/message-queue.ts +67 -0
  27. package/src/client/path-combobox.ts +271 -0
  28. package/src/client/session.ts +2174 -0
  29. package/src/client/shared.ts +99 -0
  30. package/src/client/slash-completion.ts +184 -0
  31. package/src/client/transcript-activity.ts +188 -0
  32. package/src/client/usage-format.ts +156 -0
  33. package/src/client/workspace-browser.ts +36 -0
  34. package/src/server/api.ts +652 -0
  35. package/src/server/cli.ts +63 -0
  36. package/src/server/directory-browser.ts +137 -0
  37. package/src/server/errors.ts +11 -0
  38. package/src/server/event-buffer.ts +59 -0
  39. package/src/server/extension-ui.ts +359 -0
  40. package/src/server/git-workspaces.ts +750 -0
  41. package/src/server/runtime-registry.ts +943 -0
  42. package/src/server/server.ts +248 -0
  43. package/src/server/session-repository.ts +488 -0
@@ -0,0 +1,3703 @@
1
+ // src/client/display-title.ts
2
+ var UNNAMED_SESSION_TITLE = "Unnamed session";
3
+ var MAX_FALLBACK_TITLE_CHARS = 60;
4
+ function normalizedFirstSentence(value) {
5
+ const normalized = value.replace(/\s+/gu, " ").trim();
6
+ const sentenceEnd = /[.!?。!?](?=\s|$)/u.exec(normalized);
7
+ return sentenceEnd ? normalized.slice(0, sentenceEnd.index + sentenceEnd[0].length) : normalized;
8
+ }
9
+ function boundedTitle(value) {
10
+ const characters = Array.from(value);
11
+ if (characters.length <= MAX_FALLBACK_TITLE_CHARS) {
12
+ return value;
13
+ }
14
+ const prefix = characters.slice(0, MAX_FALLBACK_TITLE_CHARS - 1).join("").trimEnd();
15
+ return `${prefix}\u2026`;
16
+ }
17
+ function displaySessionTitle(source) {
18
+ const nativeName = source.name?.trim();
19
+ if (nativeName) {
20
+ return nativeName;
21
+ }
22
+ const firstSentence = normalizedFirstSentence(source.firstMessage ?? "");
23
+ return firstSentence ? boundedTitle(firstSentence) : UNNAMED_SESSION_TITLE;
24
+ }
25
+
26
+ // src/client/event-stream.ts
27
+ var defaultScheduler = {
28
+ setTimeout: (callback, delay) => globalThis.setTimeout(callback, delay),
29
+ clearTimeout: (timer) => globalThis.clearTimeout(timer)
30
+ };
31
+ var SessionEventStream = class {
32
+ createEventSource;
33
+ heartbeatTimeoutMs;
34
+ retryDelayMs;
35
+ scheduler;
36
+ onReady;
37
+ onRuntime;
38
+ onStateChange;
39
+ source;
40
+ sessionId;
41
+ retryTimer;
42
+ watchdogTimer;
43
+ cursor;
44
+ hasConnected = false;
45
+ ready = false;
46
+ constructor(options) {
47
+ this.createEventSource = options.createEventSource ?? ((url) => new EventSource(url));
48
+ this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45e3;
49
+ this.retryDelayMs = options.retryDelayMs ?? 2e3;
50
+ this.scheduler = options.scheduler ?? defaultScheduler;
51
+ this.onReady = options.onReady;
52
+ this.onRuntime = options.onRuntime;
53
+ this.onStateChange = options.onStateChange;
54
+ }
55
+ get isReady() {
56
+ return this.ready;
57
+ }
58
+ start(sessionId) {
59
+ this.stop();
60
+ this.sessionId = sessionId;
61
+ this.open("connecting");
62
+ }
63
+ stop() {
64
+ this.clearRetry();
65
+ this.clearWatchdog();
66
+ this.source?.close();
67
+ this.source = void 0;
68
+ this.sessionId = void 0;
69
+ this.cursor = void 0;
70
+ this.hasConnected = false;
71
+ this.ready = false;
72
+ }
73
+ reconnectNow() {
74
+ if (!this.sessionId) {
75
+ return;
76
+ }
77
+ this.open("reconnecting");
78
+ }
79
+ ensureConnected() {
80
+ if (!this.ready) {
81
+ this.reconnectNow();
82
+ }
83
+ }
84
+ open(state) {
85
+ const sessionId = this.sessionId;
86
+ if (!sessionId) {
87
+ return;
88
+ }
89
+ this.clearRetry();
90
+ this.clearWatchdog();
91
+ this.source?.close();
92
+ this.ready = false;
93
+ this.onStateChange(state);
94
+ const path = `/api/sessions/${encodeURIComponent(sessionId)}/events`;
95
+ const url = this.cursor === void 0 ? path : `${path}?lastEventId=${this.cursor}`;
96
+ const source = this.createEventSource(url);
97
+ this.source = source;
98
+ this.watch(source);
99
+ source.addEventListener("ready", (rawEvent) => {
100
+ if (source !== this.source) {
101
+ return;
102
+ }
103
+ this.markActivity(source);
104
+ this.ready = true;
105
+ const recovered = this.hasConnected;
106
+ this.hasConnected = true;
107
+ this.onStateChange("connected");
108
+ this.onReady(rawEvent, recovered);
109
+ });
110
+ source.addEventListener("runtime", (rawEvent) => {
111
+ if (source !== this.source) {
112
+ return;
113
+ }
114
+ this.markActivity(source);
115
+ const event = rawEvent;
116
+ const cursor = Number(event.lastEventId);
117
+ if (event.lastEventId && Number.isSafeInteger(cursor) && cursor >= 0) {
118
+ this.cursor = cursor;
119
+ }
120
+ this.onRuntime(event);
121
+ });
122
+ source.addEventListener("heartbeat", () => {
123
+ if (source === this.source) {
124
+ this.markActivity(source);
125
+ }
126
+ });
127
+ source.onerror = () => {
128
+ if (source === this.source) {
129
+ this.fail(source);
130
+ }
131
+ };
132
+ }
133
+ fail(source) {
134
+ if (source !== this.source) {
135
+ return;
136
+ }
137
+ source.close();
138
+ this.source = void 0;
139
+ this.ready = false;
140
+ this.clearWatchdog();
141
+ this.onStateChange("reconnecting");
142
+ this.clearRetry();
143
+ this.retryTimer = this.scheduler.setTimeout(() => {
144
+ this.retryTimer = void 0;
145
+ this.open("reconnecting");
146
+ }, this.retryDelayMs);
147
+ }
148
+ markActivity(source) {
149
+ if (source !== this.source) {
150
+ return;
151
+ }
152
+ this.clearWatchdog();
153
+ this.watch(source);
154
+ }
155
+ watch(source) {
156
+ this.watchdogTimer = this.scheduler.setTimeout(() => {
157
+ this.watchdogTimer = void 0;
158
+ if (source === this.source) {
159
+ this.open("reconnecting");
160
+ }
161
+ }, this.heartbeatTimeoutMs);
162
+ }
163
+ clearRetry() {
164
+ if (this.retryTimer === void 0) {
165
+ return;
166
+ }
167
+ this.scheduler.clearTimeout(this.retryTimer);
168
+ this.retryTimer = void 0;
169
+ }
170
+ clearWatchdog() {
171
+ if (this.watchdogTimer === void 0) {
172
+ return;
173
+ }
174
+ this.scheduler.clearTimeout(this.watchdogTimer);
175
+ this.watchdogTimer = void 0;
176
+ }
177
+ };
178
+
179
+ // node_modules/marked/lib/marked.esm.js
180
+ function A() {
181
+ return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
182
+ }
183
+ var T = A();
184
+ function j(u3) {
185
+ T = u3;
186
+ }
187
+ var E = { exec: () => null };
188
+ function I(u3) {
189
+ let e = [];
190
+ return (t) => {
191
+ let n = Math.max(0, Math.min(3, t - 1)), s = e[n];
192
+ return s || (s = u3(n), e[n] = s), s;
193
+ };
194
+ }
195
+ function k(u3, e = "") {
196
+ let t = typeof u3 == "string" ? u3 : u3.source, n = { replace: (s, r) => {
197
+ let o = typeof r == "string" ? r : r.source;
198
+ return o = o.replace(m.caret, "$1"), t = t.replace(s, o), n;
199
+ }, getRegex: () => new RegExp(t, e) };
200
+ return n;
201
+ }
202
+ var Te = ((u3 = "") => {
203
+ try {
204
+ return !!new RegExp("(?<=1)(?<!1)" + u3);
205
+ } catch {
206
+ return false;
207
+ }
208
+ })();
209
+ var m = { codeRemoveIndent: /^(?: {1,4}| {0,3}\t)/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, endingSpaceTabChar: /[ \t]$/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] +\S/, listReplaceTask: /^\[[ xX]\] +/, listTaskCheckbox: /\[[ xX]\]/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (u3) => new RegExp(`^( {0,3}${u3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: I((u3) => new RegExp(`^ {0,${u3}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)), hrRegex: I((u3) => new RegExp(`^ {0,${u3}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)), fencesBeginRegex: I((u3) => new RegExp(`^ {0,${u3}}(?:\`\`\`|~~~)`)), headingBeginRegex: I((u3) => new RegExp(`^ {0,${u3}}#`)), htmlBeginRegex: I((u3) => new RegExp(`^ {0,${u3}}<(?:[a-z].*>|!--)`, "i")), blockquoteBeginRegex: I((u3) => new RegExp(`^ {0,${u3}}>`)) };
210
+ var Oe = /^(?:[ \t]*(?:\n|$))+/;
211
+ var we = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
212
+ var ye = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
213
+ var q = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
214
+ var Pe = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
215
+ var U = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
216
+ var oe = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/;
217
+ var ae = k(oe).replace(/bull/g, U).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
218
+ var Se = k(oe).replace(/bull/g, U).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
219
+ var K = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/;
220
+ var _e = /^[^\n]+/;
221
+ var W = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/;
222
+ var $e = k(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", W).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
223
+ var Le = k(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, U).getRegex();
224
+ var Q = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
225
+ var X = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
226
+ var ze = k("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][a-z0-9-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][a-z0-9-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", X).replace("tag", Q).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
227
+ var le = (u3) => k(K).replace("hr", q).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", u3).replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", Q).getRegex();
228
+ var Ee = le(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/);
229
+ var Me = le(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/);
230
+ var Ae = k(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", Me).getRegex();
231
+ var J = { blockquote: Ae, code: we, def: $e, fences: ye, heading: Pe, hr: q, html: ze, lheading: ae, list: Le, newline: Oe, paragraph: Ee, table: E, text: _e };
232
+ var se = k("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", q).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", Q).getRegex();
233
+ var Ie = { ...J, lheading: Se, table: se, paragraph: k(K).replace("hr", q).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", se).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", Q).getRegex() };
234
+ var Ce = { ...J, html: k(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", X).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: E, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: k(K).replace("hr", q).replace("heading", ` *#{1,6} *[^
235
+ ]`).replace("lheading", ae).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
236
+ var Be = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
237
+ var De = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
238
+ var ue = /^( {2,}|\\)\n(?!\s*$)/;
239
+ var qe = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
240
+ var _ = /[\p{P}\p{S}]/u;
241
+ var C = /[\s\p{P}\p{S}]/u;
242
+ var v = /[^\s\p{P}\p{S}]/u;
243
+ var ve = k(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, C).getRegex();
244
+ var He = /[\p{Pi}\p{Ps}"']/u;
245
+ var pe = /(?!~)[\p{P}\p{S}]/u;
246
+ var Ze = /(?!~)[\s\p{P}\p{S}]/u;
247
+ var Ge = /(?:[^\s\p{P}\p{S}]|~)/u;
248
+ var Qe = k(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", Te ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
249
+ var ce = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
250
+ var Ne = k(ce, "u").replace(/punct/g, _).getRegex();
251
+ var je = k(ce, "u").replace(/punct/g, pe).getRegex();
252
+ var Fe = /^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/;
253
+ var Ue = k(Fe, "u").replace(/openQuote/g, He).replace(/punct/g, _).getRegex();
254
+ var he = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)";
255
+ var Ke = k(he, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, C).replace(/punct/g, _).getRegex();
256
+ var We = k(he, "gu").replace(/notPunctSpace/g, Ge).replace(/punctSpace/g, Ze).replace(/punct/g, pe).getRegex();
257
+ var Xe = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)";
258
+ var Je = k(Xe, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, C).replace(/punct/g, _).getRegex();
259
+ var Ve = k("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, C).replace(/punct/g, _).getRegex();
260
+ var Ye = "^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)";
261
+ var et = k(Ye, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, C).replace(/punct/g, _).getRegex();
262
+ var tt = k(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, _).getRegex();
263
+ var nt = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)";
264
+ var rt = k(nt, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, C).replace(/punct/g, _).getRegex();
265
+ var st = k(/\\(punct)/, "gu").replace(/punct/g, _).getRegex();
266
+ var it = k(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
267
+ var ot = k(X).replace("(?:-->|$)", "-->").getRegex();
268
+ var at = k("^comment|^</[a-zA-Z][a-zA-Z0-9-]*\\s*>|^<[a-zA-Z][a-zA-Z0-9-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", ot).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
269
+ var lt = /\[(?:\\[\s\S]|[^\[\]\\])*\]/;
270
+ var G = k(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace("brackets", lt).getRegex();
271
+ var ut = k(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label", G).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
272
+ var ke = k(/^!?\[(label)\]\[(ref)\]/).replace("label", G).replace("ref", W).getRegex();
273
+ var de = k(/^!?\[(ref)\](?:\[\])?/).replace("ref", W).getRegex();
274
+ var pt = k("reflink|nolink(?!\\()", "g").replace("reflink", ke).replace("nolink", de).getRegex();
275
+ var ie = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
276
+ var V = { _backpedal: E, anyPunctuation: st, autolink: it, blockSkip: Qe, br: ue, code: De, del: E, delLDelim: E, delRDelim: E, emStrongLDelim: Ne, emStrongRDelimAst: Ke, emStrongRDelimUnd: Ve, escape: Be, link: ut, nolink: de, punctuation: ve, reflink: ke, reflinkSearch: pt, tag: at, text: qe, url: E };
277
+ var ct = { ...V, emStrongLDelim: Ue, emStrongRDelimAst: Je, emStrongRDelimUnd: et, link: k(/^!?\[(label)\]\((.*?)\)/).replace("label", G).getRegex(), reflink: k(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", G).getRegex() };
278
+ var F = { ...V, emStrongRDelimAst: We, emStrongLDelim: je, delLDelim: tt, delRDelim: rt, url: k(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", ie).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: k(/^(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol", ie).getRegex() };
279
+ var ht = { ...F, br: k(ue).replace("{2,}", "*").getRegex(), text: k(F.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
280
+ var H = { normal: J, gfm: Ie, pedantic: Ce };
281
+ var B = { normal: V, gfm: F, breaks: ht, pedantic: ct };
282
+ var kt = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
283
+ var ge = (u3) => kt[u3];
284
+ function R(u3, e) {
285
+ if (e) {
286
+ if (m.escapeTest.test(u3)) return u3.replace(m.escapeReplace, ge);
287
+ } else if (m.escapeTestNoEncode.test(u3)) return u3.replace(m.escapeReplaceNoEncode, ge);
288
+ return u3;
289
+ }
290
+ function Y(u3) {
291
+ try {
292
+ u3 = encodeURI(u3).replace(m.percentDecode, "%");
293
+ } catch {
294
+ return null;
295
+ }
296
+ return u3;
297
+ }
298
+ function ee(u3, e) {
299
+ let t = u3.replace(m.findPipe, (r, o, i) => {
300
+ let l = false, a = o;
301
+ for (; --a >= 0 && i[a] === "\\"; ) l = !l;
302
+ return l ? "|" : " |";
303
+ }), n = t.split(m.splitPipe), s = 0;
304
+ if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e) if (n.length > e) n.splice(e);
305
+ else for (; n.length < e; ) n.push("");
306
+ for (; s < n.length; s++) n[s] = n[s].trim().replace(m.slashPipe, "|");
307
+ return n;
308
+ }
309
+ function $(u3, e, t) {
310
+ let n = u3.length;
311
+ if (n === 0) return "";
312
+ let s = 0;
313
+ for (; s < n; ) {
314
+ let r = u3.charAt(n - s - 1);
315
+ if (r === e && !t) s++;
316
+ else if (r !== e && t) s++;
317
+ else break;
318
+ }
319
+ return u3.slice(0, n - s);
320
+ }
321
+ function te(u3) {
322
+ let e = u3.split(`
323
+ `), t = e.length - 1;
324
+ for (; t >= 0 && m.blankLine.test(e[t]); ) t--;
325
+ return e.length - t <= 2 ? u3 : e.slice(0, t + 1).join(`
326
+ `);
327
+ }
328
+ function fe(u3, e) {
329
+ if (u3.indexOf(e[1]) === -1) return -1;
330
+ let t = 0;
331
+ for (let n = 0; n < u3.length; n++) if (u3[n] === "\\") n++;
332
+ else if (u3[n] === e[0]) t++;
333
+ else if (u3[n] === e[1] && (t--, t < 0)) return n;
334
+ return t > 0 ? -2 : -1;
335
+ }
336
+ function me(u3, e = 0) {
337
+ let t = e, n = "";
338
+ for (let s of u3) if (s === " ") {
339
+ let r = 4 - t % 4;
340
+ n += " ".repeat(r), t += r;
341
+ } else n += s, t++;
342
+ return n;
343
+ }
344
+ function xe(u3, e, t, n, s) {
345
+ let r = e.href, o = e.title || null, i = u3[1].replace(s.other.outputLinkReplace, "$1"), l = u3[0].charAt(0) === "!";
346
+ n.state.inLink = true;
347
+ let a = n.state.linkEmitted, p = n.state.inRawBlock;
348
+ n.state.linkEmitted = false;
349
+ let c = n.inlineTokens(i), h = n.state.linkEmitted;
350
+ if (n.state.linkEmitted = a, n.state.inLink = false, !l) {
351
+ if (h) {
352
+ n.state.inRawBlock = p;
353
+ return;
354
+ }
355
+ n.state.linkEmitted = true;
356
+ }
357
+ return { type: l ? "image" : "link", raw: t, href: r, title: o, text: i, tokens: c };
358
+ }
359
+ function dt(u3, e, t) {
360
+ let n = u3.match(t.other.indentCodeCompensation);
361
+ if (n === null) return e;
362
+ let s = n[1];
363
+ return e.split(`
364
+ `).map((r) => {
365
+ let o = r.match(t.other.beginningSpace);
366
+ if (o === null) return r;
367
+ let [i] = o;
368
+ return r.slice(Math.min(i.length, s.length));
369
+ }).join(`
370
+ `);
371
+ }
372
+ var y = class {
373
+ options;
374
+ rules;
375
+ lexer;
376
+ constructor(e) {
377
+ this.options = e || T;
378
+ }
379
+ space(e) {
380
+ let t = this.rules.block.newline.exec(e);
381
+ if (t && t[0].length > 0) return { type: "space", raw: t[0] };
382
+ }
383
+ code(e) {
384
+ let t = this.rules.block.code.exec(e);
385
+ if (t) {
386
+ let n = this.options.pedantic ? t[0] : te(t[0]), s = n.replace(this.rules.other.codeRemoveIndent, "");
387
+ return { type: "code", raw: n, codeBlockStyle: "indented", text: s };
388
+ }
389
+ }
390
+ fences(e) {
391
+ let t = this.rules.block.fences.exec(e);
392
+ if (t) {
393
+ let n = t[0], s = dt(n, t[3] || "", this.rules);
394
+ return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: s };
395
+ }
396
+ }
397
+ heading(e) {
398
+ let t = this.rules.block.heading.exec(e);
399
+ if (t) {
400
+ let n = t[2].trim();
401
+ if (this.rules.other.endingHash.test(n)) {
402
+ let s = $(n, "#");
403
+ (this.options.pedantic || !s || this.rules.other.endingSpaceTabChar.test(s)) && (n = s.trim());
404
+ }
405
+ return { type: "heading", raw: $(t[0], `
406
+ `), depth: t[1].length, text: n, tokens: this.lexer.inline(n) };
407
+ }
408
+ }
409
+ hr(e) {
410
+ let t = this.rules.block.hr.exec(e);
411
+ if (t) return { type: "hr", raw: $(t[0], `
412
+ `) };
413
+ }
414
+ blockquote(e) {
415
+ let t = this.rules.block.blockquote.exec(e);
416
+ if (t) {
417
+ let n = $(t[0], `
418
+ `).split(`
419
+ `), s = "", r = "", o = [];
420
+ for (; n.length > 0; ) {
421
+ let i = false, l = [], a;
422
+ for (a = 0; a < n.length; a++) if (this.rules.other.blockquoteStart.test(n[a])) l.push(n[a]), i = true;
423
+ else if (!i) l.push(n[a]);
424
+ else break;
425
+ n = n.slice(a);
426
+ let p = l.join(`
427
+ `), c = p.replace(this.rules.other.blockquoteSetextReplace, `
428
+ $1`).replace(this.rules.other.blockquoteSetextReplace2, "");
429
+ s = s ? `${s}
430
+ ${p}` : p, r = r ? `${r}
431
+ ${c}` : c;
432
+ let h = this.lexer.state.top;
433
+ if (this.lexer.state.top = true, this.lexer.blockTokens(c, o, true), this.lexer.state.top = h, n.length === 0) break;
434
+ let d = o.at(-1);
435
+ if (d?.type === "code") break;
436
+ if (d?.type === "blockquote") {
437
+ let O = d, g = n.join(`
438
+ `), w = O.raw + `
439
+ ` + g.replace(this.rules.other.blockquoteSetextReplace2, ""), z = this.blockquote(w);
440
+ o[o.length - 1] = z, s = `${s}
441
+ ${g}`, r = r.substring(0, r.length - O.text.length) + z.text;
442
+ break;
443
+ } else if (d?.type === "list") {
444
+ let O = d, g = O.raw + `
445
+ ` + n.join(`
446
+ `), w = this.list(g);
447
+ o[o.length - 1] = w, s = s.substring(0, s.length - d.raw.length) + w.raw, r = r.substring(0, r.length - O.raw.length) + w.raw, n = g.substring(o.at(-1).raw.length).split(`
448
+ `);
449
+ continue;
450
+ }
451
+ }
452
+ return { type: "blockquote", raw: s, tokens: o, text: r };
453
+ }
454
+ }
455
+ list(e) {
456
+ let t = this.rules.block.list.exec(e);
457
+ if (t) {
458
+ let n = t[1].trim(), s = n.length > 1, r = { type: "list", raw: "", ordered: s, start: s ? +n.slice(0, -1) : "", loose: false, items: [] };
459
+ n = s ? `\\d{1,9}\\${n.slice(-1)}` : `\\${n}`, this.options.pedantic && (n = s ? n : "[*+-]");
460
+ let o = this.rules.other.listItemRegex(n), i = false;
461
+ for (; e; ) {
462
+ let a = false, p = "", c = "";
463
+ if (!(t = o.exec(e)) || this.rules.block.hr.test(e)) break;
464
+ p = t[0], e = e.substring(p.length);
465
+ let h = me(t[2].split(`
466
+ `, 1)[0], t[1].length), d = e.split(`
467
+ `, 1)[0], O = !h.trim(), g = 0;
468
+ if (this.options.pedantic ? (g = 2, c = h.trimStart()) : O ? g = t[1].length + 1 : (g = h.search(this.rules.other.nonSpaceChar), g = g > 4 ? 1 : g, c = h.slice(g), g += t[1].length), O && this.rules.other.blankLine.test(d) && (p += d + `
469
+ `, e = e.substring(d.length + 1), a = true), !a) {
470
+ let w = this.rules.other.nextBulletRegex(g), z = this.rules.other.hrRegex(g), ne = this.rules.other.fencesBeginRegex(g), re = this.rules.other.headingBeginRegex(g), be = this.rules.other.htmlBeginRegex(g), Re = this.rules.other.blockquoteBeginRegex(g);
471
+ for (; e; ) {
472
+ let N = e.split(`
473
+ `, 1)[0], D;
474
+ if (d = N, this.options.pedantic ? (d = d.replace(this.rules.other.listReplaceNesting, " "), D = d) : D = d.replace(this.rules.other.tabCharGlobal, " "), ne.test(d) || re.test(d) || be.test(d) || Re.test(d) || w.test(d) || z.test(d)) break;
475
+ if (D.search(this.rules.other.nonSpaceChar) >= g || !d.trim()) c += `
476
+ ` + D.slice(g);
477
+ else {
478
+ if (O || h.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || ne.test(h) || re.test(h) || z.test(h)) break;
479
+ c += `
480
+ ` + d;
481
+ }
482
+ O = !d.trim(), p += N + `
483
+ `, e = e.substring(N.length + 1), h = D.slice(g);
484
+ }
485
+ }
486
+ r.loose || (i ? r.loose = true : this.rules.other.doubleBlankLine.test(p) && (i = true)), r.items.push({ type: "list_item", raw: p, task: !!this.options.gfm && this.rules.other.listIsTask.test(c), loose: false, text: c, tokens: [] }), r.raw += p;
487
+ }
488
+ let l = r.items.at(-1);
489
+ if (l) l.raw = l.raw.trimEnd(), l.text = l.text.trimEnd();
490
+ else return;
491
+ r.raw = r.raw.trimEnd();
492
+ for (let a of r.items) if (this.lexer.state.top = false, a.tokens = this.lexer.blockTokens(a.text, []), !r.loose) {
493
+ let p = a.tokens.filter((h) => h.type === "space"), c = p.length > 0 && p.some((h) => this.rules.other.anyLine.test(h.raw));
494
+ r.loose = c;
495
+ }
496
+ for (let a of r.items) {
497
+ let p = a.tokens[0];
498
+ if (a.task && (p?.type === "text" || p?.type === "paragraph")) {
499
+ a.text = a.text.replace(this.rules.other.listReplaceTask, ""), p.raw = p.raw.replace(this.rules.other.listReplaceTask, ""), p.text = p.text.replace(this.rules.other.listReplaceTask, "");
500
+ for (let h = this.lexer.inlineQueue.length - 1; h >= 0; h--) if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[h].src)) {
501
+ this.lexer.inlineQueue[h].src = this.lexer.inlineQueue[h].src.replace(this.rules.other.listReplaceTask, "");
502
+ break;
503
+ }
504
+ let c = this.rules.other.listTaskCheckbox.exec(a.raw);
505
+ if (c) {
506
+ let h = { type: "checkbox", raw: c[0] + " ", checked: c[0] !== "[ ]" };
507
+ a.checked = h.checked, r.loose ? a.tokens[0] && ["paragraph", "text"].includes(a.tokens[0].type) && "tokens" in a.tokens[0] && a.tokens[0].tokens ? (a.tokens[0].raw = h.raw + a.tokens[0].raw, a.tokens[0].text = h.raw + a.tokens[0].text, a.tokens[0].tokens.unshift(h)) : a.tokens.unshift({ type: "paragraph", raw: h.raw, text: h.raw, tokens: [h] }) : a.tokens.unshift(h);
508
+ }
509
+ } else a.task && (a.task = false);
510
+ }
511
+ if (r.loose) for (let a of r.items) {
512
+ a.loose = true;
513
+ for (let p of a.tokens) p.type === "text" && (p.type = "paragraph");
514
+ }
515
+ return r;
516
+ }
517
+ }
518
+ html(e) {
519
+ let t = this.rules.block.html.exec(e);
520
+ if (t) {
521
+ let n = te(t[0]);
522
+ return { type: "html", block: true, raw: n, pre: t[1] === "pre" || t[1] === "script" || t[1] === "style", text: n };
523
+ }
524
+ }
525
+ def(e) {
526
+ let t = this.rules.block.def.exec(e);
527
+ if (t) {
528
+ let n = t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal, " "), s = t[2] ? t[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", r = t[3] ? t[3].substring(1, t[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t[3];
529
+ return { type: "def", tag: n, raw: $(t[0], `
530
+ `), href: s, title: r };
531
+ }
532
+ }
533
+ table(e) {
534
+ let t = this.rules.block.table.exec(e);
535
+ if (!t || !this.rules.other.tableDelimiter.test(t[2])) return;
536
+ let n = ee(t[1]), s = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), r = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(`
537
+ `) : [], o = { type: "table", raw: $(t[0], `
538
+ `), header: [], align: [], rows: [] };
539
+ if (n.length === s.length) {
540
+ for (let i of s) this.rules.other.tableAlignRight.test(i) ? o.align.push("right") : this.rules.other.tableAlignCenter.test(i) ? o.align.push("center") : this.rules.other.tableAlignLeft.test(i) ? o.align.push("left") : o.align.push(null);
541
+ for (let i = 0; i < n.length; i++) o.header.push({ text: n[i], tokens: this.lexer.inline(n[i]), header: true, align: o.align[i] });
542
+ for (let i of r) o.rows.push(ee(i, o.header.length).map((l, a) => ({ text: l, tokens: this.lexer.inline(l), header: false, align: o.align[a] })));
543
+ return o;
544
+ }
545
+ }
546
+ lheading(e) {
547
+ let t = this.rules.block.lheading.exec(e);
548
+ if (t) {
549
+ let n = t[1].trim();
550
+ return { type: "heading", raw: $(t[0], `
551
+ `), depth: t[2].charAt(0) === "=" ? 1 : 2, text: n, tokens: this.lexer.inline(n) };
552
+ }
553
+ }
554
+ paragraph(e) {
555
+ let t = this.rules.block.paragraph.exec(e);
556
+ if (t) {
557
+ let n = t[1].charAt(t[1].length - 1) === `
558
+ ` ? t[1].slice(0, -1) : t[1];
559
+ return { type: "paragraph", raw: t[0], text: n, tokens: this.lexer.inline(n) };
560
+ }
561
+ }
562
+ text(e) {
563
+ let t = this.rules.block.text.exec(e);
564
+ if (t) return { type: "text", raw: t[0], text: t[0], tokens: this.lexer.inline(t[0]) };
565
+ }
566
+ escape(e) {
567
+ let t = this.rules.inline.escape.exec(e);
568
+ if (t) return { type: "escape", raw: t[0], text: t[1] };
569
+ }
570
+ tag(e) {
571
+ let t = this.rules.inline.tag.exec(e);
572
+ if (t) return !this.lexer.state.inLink && this.rules.other.startATag.test(t[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t[0] };
573
+ }
574
+ link(e) {
575
+ let t = this.rules.inline.link.exec(e);
576
+ if (t) {
577
+ let n = t[2].trim();
578
+ if (!this.options.pedantic && this.rules.other.startAngleBracket.test(n)) {
579
+ if (!this.rules.other.endAngleBracket.test(n)) return;
580
+ let o = $(n.slice(0, -1), "\\");
581
+ if ((n.length - o.length) % 2 === 0) return;
582
+ } else {
583
+ let o = fe(t[2], "()");
584
+ if (o === -2) return;
585
+ if (o > -1) {
586
+ let l = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + o;
587
+ t[2] = t[2].substring(0, o), t[0] = t[0].substring(0, l).trim(), t[3] = "";
588
+ }
589
+ }
590
+ let s = t[2], r = "";
591
+ if (this.options.pedantic) {
592
+ let o = this.rules.other.pedanticHrefTitle.exec(s);
593
+ o && (s = o[1], r = o[3]);
594
+ } else r = t[3] ? t[3].slice(1, -1) : "";
595
+ return s = s.trim(), this.rules.other.startAngleBracket.test(s) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(n) ? s = s.slice(1) : s = s.slice(1, -1)), xe(t, { href: s && s.replace(this.rules.inline.anyPunctuation, "$1"), title: r && r.replace(this.rules.inline.anyPunctuation, "$1") }, t[0], this.lexer, this.rules);
596
+ }
597
+ }
598
+ reflink(e, t) {
599
+ let n;
600
+ if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
601
+ let s = (n[2] || n[1]).replace(this.rules.other.multipleSpaceGlobal, " "), r = t[s.toLowerCase()];
602
+ if (!r) {
603
+ let o = n[0].charAt(0);
604
+ return { type: "text", raw: o, text: o };
605
+ }
606
+ return xe(n, r, n[0], this.lexer, this.rules);
607
+ }
608
+ }
609
+ emStrong(e, t, n = "") {
610
+ let s = this.rules.inline.emStrongLDelim.exec(e);
611
+ if (!s || !s[1] && !s[2] && !s[3] && !s[4] || s[4] && n.match(this.rules.other.unicodeAlphaNumeric)) return;
612
+ if (!(s[1] || s[3] || "") || !n || this.rules.inline.punctuation.exec(n)) {
613
+ let o = [...s[0]].length - 1, i, l, a = o, p = 0, c = s[0][0], h = n === c, d = c === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
614
+ for (d.lastIndex = 0, t = t.slice(-1 * e.length + o); (s = d.exec(t)) !== null; ) {
615
+ if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i) continue;
616
+ if (l = [...i].length, s[3] || s[4]) {
617
+ a += l;
618
+ continue;
619
+ } else if (s[5] || s[6]) {
620
+ if (o % 3 && !((o + l) % 3)) {
621
+ p += l;
622
+ continue;
623
+ }
624
+ if (h) break;
625
+ }
626
+ if (a -= l, a > 0) continue;
627
+ l = Math.min(l, l + a + p);
628
+ let O = [...s[0]][0].length, g = e.slice(0, o + s.index + O + l);
629
+ if (Math.min(o, l) % 2) {
630
+ let z = g.slice(1, -1);
631
+ return { type: "em", raw: g, text: z, tokens: this.lexer.inlineTokens(z) };
632
+ }
633
+ let w = g.slice(2, -2);
634
+ return { type: "strong", raw: g, text: w, tokens: this.lexer.inlineTokens(w) };
635
+ }
636
+ }
637
+ }
638
+ codespan(e) {
639
+ let t = this.rules.inline.code.exec(e);
640
+ if (t) {
641
+ let n = t[2].replace(this.rules.other.newLineCharGlobal, " "), s = this.rules.other.nonSpaceChar.test(n), r = this.rules.other.startingSpaceChar.test(n) && this.rules.other.endingSpaceChar.test(n);
642
+ return s && r && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t[0], text: n };
643
+ }
644
+ }
645
+ br(e) {
646
+ let t = this.rules.inline.br.exec(e);
647
+ if (t) return { type: "br", raw: t[0] };
648
+ }
649
+ del(e, t, n = "") {
650
+ let s = this.rules.inline.delLDelim.exec(e);
651
+ if (!s) return;
652
+ if (!(s[1] || "") || !n || this.rules.inline.punctuation.exec(n)) {
653
+ let o = [...s[0]].length - 1, i, l, a = o, p = this.rules.inline.delRDelim;
654
+ for (p.lastIndex = 0, t = t.slice(-1 * e.length + o); (s = p.exec(t)) !== null; ) {
655
+ if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i || (l = [...i].length, l !== o)) continue;
656
+ if (s[3] || s[4]) {
657
+ a += l;
658
+ continue;
659
+ }
660
+ if (a -= l, a > 0) continue;
661
+ l = Math.min(l, l + a);
662
+ let c = [...s[0]][0].length, h = e.slice(0, o + s.index + c + l), d = h.slice(o, -o);
663
+ return { type: "del", raw: h, text: d, tokens: this.lexer.inlineTokens(d) };
664
+ }
665
+ }
666
+ }
667
+ autolink(e) {
668
+ let t = this.rules.inline.autolink.exec(e);
669
+ if (t) {
670
+ let n, s;
671
+ return t[2] === "@" ? (n = t[1], s = "mailto:" + n) : (n = t[1], s = n), { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
672
+ }
673
+ }
674
+ url(e) {
675
+ let t;
676
+ if (t = this.rules.inline.url.exec(e)) {
677
+ let n, s;
678
+ if (t[2] === "@") n = t[0], s = "mailto:" + n;
679
+ else {
680
+ let r;
681
+ do
682
+ r = t[0], t[0] = this.rules.inline._backpedal.exec(t[0])?.[0] ?? "";
683
+ while (r !== t[0]);
684
+ n = t[0], t[1] === "www." ? s = "http://" + t[0] : s = t[0];
685
+ }
686
+ return { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
687
+ }
688
+ }
689
+ inlineText(e) {
690
+ let t = this.rules.inline.text.exec(e);
691
+ if (t) {
692
+ let n = this.lexer.state.inRawBlock;
693
+ return { type: "text", raw: t[0], text: t[0], escaped: n };
694
+ }
695
+ }
696
+ };
697
+ var x = class u {
698
+ tokens;
699
+ options;
700
+ state;
701
+ inlineQueue;
702
+ tokenizer;
703
+ constructor(e) {
704
+ this.tokens = [], this.tokens.links = /* @__PURE__ */ Object.create(null), this.options = e || T, this.options.tokenizer = this.options.tokenizer || new y(), this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, linkEmitted: false, top: true };
705
+ let t = { other: m, block: H.normal, inline: B.normal };
706
+ this.options.pedantic ? (t.block = H.pedantic, t.inline = B.pedantic) : this.options.gfm && (t.block = H.gfm, this.options.breaks ? t.inline = B.breaks : t.inline = B.gfm), this.tokenizer.rules = t;
707
+ }
708
+ static get rules() {
709
+ return { block: H, inline: B };
710
+ }
711
+ static lex(e, t) {
712
+ return new u(t).lex(e);
713
+ }
714
+ static lexInline(e, t) {
715
+ return new u(t).inlineTokens(e);
716
+ }
717
+ lex(e) {
718
+ e = e.replace(m.carriageReturn, `
719
+ `), this.blockTokens(e, this.tokens);
720
+ for (let t = 0; t < this.inlineQueue.length; t++) {
721
+ let n = this.inlineQueue[t];
722
+ this.inlineTokens(n.src, n.tokens);
723
+ }
724
+ return this.inlineQueue = [], this.tokens;
725
+ }
726
+ blockTokens(e, t = [], n = false) {
727
+ this.tokenizer.lexer = this, this.options.pedantic && (e = e.replace(m.tabCharGlobal, " ").replace(m.spaceLine, ""));
728
+ let s = 1 / 0;
729
+ for (; e; ) {
730
+ if (e.length < s) s = e.length;
731
+ else {
732
+ this.infiniteLoopError(e.charCodeAt(0));
733
+ break;
734
+ }
735
+ let r;
736
+ if (this.options.extensions?.block?.some((i) => (r = i.call({ lexer: this }, e, t)) ? (e = e.substring(r.raw.length), t.push(r), true) : false)) continue;
737
+ if (r = this.tokenizer.space(e)) {
738
+ e = e.substring(r.raw.length);
739
+ let i = t.at(-1);
740
+ r.raw.length === 1 && i !== void 0 ? i.raw += `
741
+ ` : t.push(r);
742
+ continue;
743
+ }
744
+ if (r = this.tokenizer.code(e)) {
745
+ e = e.substring(r.raw.length);
746
+ let i = t.at(-1);
747
+ i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
748
+ `) ? "" : `
749
+ `) + r.raw, i.text += `
750
+ ` + r.text, this.inlineQueue.at(-1).src = i.text) : t.push(r);
751
+ continue;
752
+ }
753
+ if (r = this.tokenizer.fences(e)) {
754
+ e = e.substring(r.raw.length), t.push(r);
755
+ continue;
756
+ }
757
+ if (r = this.tokenizer.heading(e)) {
758
+ e = e.substring(r.raw.length), t.push(r);
759
+ continue;
760
+ }
761
+ if (r = this.tokenizer.hr(e)) {
762
+ e = e.substring(r.raw.length), t.push(r);
763
+ continue;
764
+ }
765
+ if (r = this.tokenizer.blockquote(e)) {
766
+ e = e.substring(r.raw.length), t.push(r);
767
+ continue;
768
+ }
769
+ if (r = this.tokenizer.list(e)) {
770
+ e = e.substring(r.raw.length), t.push(r);
771
+ continue;
772
+ }
773
+ if (r = this.tokenizer.html(e)) {
774
+ e = e.substring(r.raw.length), t.push(r);
775
+ continue;
776
+ }
777
+ if (r = this.tokenizer.def(e)) {
778
+ e = e.substring(r.raw.length);
779
+ let i = t.at(-1);
780
+ i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
781
+ `) ? "" : `
782
+ `) + r.raw, i.text += `
783
+ ` + r.raw, this.inlineQueue.at(-1).src = i.text) : this.tokens.links[r.tag] || (this.tokens.links[r.tag] = { href: r.href, title: r.title }, t.push(r));
784
+ continue;
785
+ }
786
+ if (r = this.tokenizer.table(e)) {
787
+ e = e.substring(r.raw.length), t.push(r);
788
+ continue;
789
+ }
790
+ if (r = this.tokenizer.lheading(e)) {
791
+ e = e.substring(r.raw.length), t.push(r);
792
+ continue;
793
+ }
794
+ let o = e;
795
+ if (this.options.extensions?.startBlock) {
796
+ let i = 1 / 0, l = e.slice(1), a;
797
+ this.options.extensions.startBlock.forEach((p) => {
798
+ a = p.call({ lexer: this }, l), typeof a == "number" && a >= 0 && (i = Math.min(i, a));
799
+ }), i < 1 / 0 && i >= 0 && (o = e.substring(0, i + 1));
800
+ }
801
+ if (this.state.top && (r = this.tokenizer.paragraph(o))) {
802
+ let i = t.at(-1);
803
+ n && i?.type === "paragraph" ? (i.raw += (i.raw.endsWith(`
804
+ `) ? "" : `
805
+ `) + r.raw, i.text += `
806
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r), n = o.length !== e.length, e = e.substring(r.raw.length);
807
+ continue;
808
+ }
809
+ if (r = this.tokenizer.text(e)) {
810
+ e = e.substring(r.raw.length);
811
+ let i = t.at(-1);
812
+ i?.type === "text" ? (i.raw += (i.raw.endsWith(`
813
+ `) ? "" : `
814
+ `) + r.raw, i.text += `
815
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r);
816
+ continue;
817
+ }
818
+ if (e) {
819
+ this.infiniteLoopError(e.charCodeAt(0));
820
+ break;
821
+ }
822
+ }
823
+ return this.state.top = true, t;
824
+ }
825
+ inline(e, t = []) {
826
+ return this.inlineQueue.push({ src: e, tokens: t }), t;
827
+ }
828
+ linkInText(e) {
829
+ if (!e.includes("[")) return false;
830
+ let t = this.tokenizer.rules.inline.link;
831
+ for (let n of e.matchAll(this.tokenizer.rules.inline.blockSkip)) if (t.test(n[0]) && e.charAt(n.index - 1) !== "!") return true;
832
+ for (let n of e.matchAll(this.tokenizer.rules.inline.reflinkSearch)) {
833
+ let s = n[0], r = s.lastIndexOf("[");
834
+ if (!(s.charAt(0) === "!" || !Object.hasOwn(this.tokens.links, s.slice(r + 1, -1))) && !(r > 1 && this.linkInText(s.slice(1, r - 1)))) return true;
835
+ }
836
+ return false;
837
+ }
838
+ inlineTokens(e, t = []) {
839
+ this.tokenizer.lexer = this;
840
+ let n = e;
841
+ if (this.tokens.links && e.includes("[")) {
842
+ let i = this.tokenizer.rules.inline.reflinkSearch, l = (a) => {
843
+ let p = a.lastIndexOf("[");
844
+ if (!Object.hasOwn(this.tokens.links, a.slice(p + 1, -1))) return a;
845
+ if (p > 1 && a.charAt(0) !== "!") {
846
+ let c = a.slice(1, p - 1);
847
+ if (this.linkInText(c)) return "[" + c.replace(i, l) + "][" + "a".repeat(a.length - p - 2) + "]";
848
+ }
849
+ return "[" + "a".repeat(a.length - 2) + "]";
850
+ };
851
+ n = n.replace(i, l);
852
+ }
853
+ n = n.replace(this.tokenizer.rules.inline.anyPunctuation, (i) => "+".repeat(i.length)), n = n.replace(this.tokenizer.rules.inline.blockSkip, (i, l, a) => {
854
+ let p = a ? a.length : 0;
855
+ return i.slice(0, p) + "[" + "a".repeat(i.length - p - 2) + "]";
856
+ }), n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n;
857
+ let s = false, r = "", o = 1 / 0;
858
+ for (; e; ) {
859
+ if (e.length < o) o = e.length;
860
+ else {
861
+ this.infiniteLoopError(e.charCodeAt(0));
862
+ break;
863
+ }
864
+ s || (r = ""), s = false;
865
+ let i;
866
+ if (this.options.extensions?.inline?.some((a) => (i = a.call({ lexer: this }, e, t)) ? (e = e.substring(i.raw.length), t.push(i), true) : false)) continue;
867
+ if (i = this.tokenizer.escape(e)) {
868
+ e = e.substring(i.raw.length), t.push(i);
869
+ continue;
870
+ }
871
+ if (i = this.tokenizer.tag(e)) {
872
+ e = e.substring(i.raw.length), t.push(i);
873
+ continue;
874
+ }
875
+ if (i = this.tokenizer.link(e)) {
876
+ e = e.substring(i.raw.length), t.push(i);
877
+ continue;
878
+ }
879
+ if (i = this.tokenizer.reflink(e, this.tokens.links)) {
880
+ e = e.substring(i.raw.length);
881
+ let a = t.at(-1);
882
+ i.type === "text" && a?.type === "text" ? (a.raw += i.raw, a.text += i.text) : t.push(i);
883
+ continue;
884
+ }
885
+ if (i = this.tokenizer.emStrong(e, n, r)) {
886
+ e = e.substring(i.raw.length), t.push(i);
887
+ continue;
888
+ }
889
+ if (i = this.tokenizer.codespan(e)) {
890
+ e = e.substring(i.raw.length), t.push(i);
891
+ continue;
892
+ }
893
+ if (i = this.tokenizer.br(e)) {
894
+ e = e.substring(i.raw.length), t.push(i);
895
+ continue;
896
+ }
897
+ if (i = this.tokenizer.del(e, n, r)) {
898
+ e = e.substring(i.raw.length), t.push(i);
899
+ continue;
900
+ }
901
+ if (i = this.tokenizer.autolink(e)) {
902
+ e = e.substring(i.raw.length), t.push(i);
903
+ continue;
904
+ }
905
+ if (!this.state.inLink && (i = this.tokenizer.url(e))) {
906
+ e = e.substring(i.raw.length), t.push(i);
907
+ continue;
908
+ }
909
+ let l = e;
910
+ if (this.options.extensions?.startInline) {
911
+ let a = 1 / 0, p = e.slice(1), c;
912
+ this.options.extensions.startInline.forEach((h) => {
913
+ c = h.call({ lexer: this }, p), typeof c == "number" && c >= 0 && (a = Math.min(a, c));
914
+ }), a < 1 / 0 && a >= 0 && (l = e.substring(0, a + 1));
915
+ }
916
+ if (i = this.tokenizer.inlineText(l)) {
917
+ e = e.substring(i.raw.length), i.raw.slice(-1) !== "_" && (r = i.raw.slice(-1)), s = true;
918
+ let a = t.at(-1);
919
+ a?.type === "text" ? (a.raw += i.raw, a.text += i.text) : t.push(i);
920
+ continue;
921
+ }
922
+ if (e) {
923
+ this.infiniteLoopError(e.charCodeAt(0));
924
+ break;
925
+ }
926
+ }
927
+ return t;
928
+ }
929
+ infiniteLoopError(e) {
930
+ let t = "Infinite loop on byte: " + e;
931
+ if (this.options.silent) console.error(t);
932
+ else throw new Error(t);
933
+ }
934
+ };
935
+ var P = class {
936
+ options;
937
+ parser;
938
+ constructor(e) {
939
+ this.options = e || T;
940
+ }
941
+ space(e) {
942
+ return "";
943
+ }
944
+ code({ text: e, lang: t, escaped: n }) {
945
+ let s = (t || "").match(m.notSpaceStart)?.[0], r = e ? e.replace(m.endingNewline, "") + `
946
+ ` : "";
947
+ return s ? '<pre><code class="language-' + R(s) + '">' + (n ? r : R(r, true)) + `</code></pre>
948
+ ` : "<pre><code>" + (n ? r : R(r, true)) + `</code></pre>
949
+ `;
950
+ }
951
+ blockquote({ tokens: e }) {
952
+ return `<blockquote>
953
+ ${this.parser.parse(e)}</blockquote>
954
+ `;
955
+ }
956
+ html({ text: e }) {
957
+ return e;
958
+ }
959
+ def(e) {
960
+ return "";
961
+ }
962
+ heading({ tokens: e, depth: t }) {
963
+ return `<h${t}>${this.parser.parseInline(e)}</h${t}>
964
+ `;
965
+ }
966
+ hr(e) {
967
+ return `<hr>
968
+ `;
969
+ }
970
+ list(e) {
971
+ let t = e.ordered, n = e.start, s = "";
972
+ for (let i = 0; i < e.items.length; i++) {
973
+ let l = e.items[i];
974
+ s += this.listitem(l);
975
+ }
976
+ let r = t ? "ol" : "ul", o = t && n !== 1 ? ' start="' + n + '"' : "";
977
+ return "<" + r + o + `>
978
+ ` + s + "</" + r + `>
979
+ `;
980
+ }
981
+ listitem(e) {
982
+ return `<li>${this.parser.parse(e.tokens)}</li>
983
+ `;
984
+ }
985
+ checkbox({ checked: e }) {
986
+ return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox"> ';
987
+ }
988
+ paragraph({ tokens: e }) {
989
+ return `<p>${this.parser.parseInline(e)}</p>
990
+ `;
991
+ }
992
+ table(e) {
993
+ let t = "", n = "";
994
+ for (let r = 0; r < e.header.length; r++) n += this.tablecell(e.header[r]);
995
+ t += this.tablerow({ text: n });
996
+ let s = "";
997
+ for (let r = 0; r < e.rows.length; r++) {
998
+ let o = e.rows[r];
999
+ n = "";
1000
+ for (let i = 0; i < o.length; i++) n += this.tablecell(o[i]);
1001
+ s += this.tablerow({ text: n });
1002
+ }
1003
+ return s && (s = `<tbody>${s}</tbody>`), `<table>
1004
+ <thead>
1005
+ ` + t + `</thead>
1006
+ ` + s + `</table>
1007
+ `;
1008
+ }
1009
+ tablerow({ text: e }) {
1010
+ return `<tr>
1011
+ ${e}</tr>
1012
+ `;
1013
+ }
1014
+ tablecell(e) {
1015
+ let t = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
1016
+ return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t + `</${n}>
1017
+ `;
1018
+ }
1019
+ strong({ tokens: e }) {
1020
+ return `<strong>${this.parser.parseInline(e)}</strong>`;
1021
+ }
1022
+ em({ tokens: e }) {
1023
+ return `<em>${this.parser.parseInline(e)}</em>`;
1024
+ }
1025
+ codespan({ text: e }) {
1026
+ return `<code>${R(e, true)}</code>`;
1027
+ }
1028
+ br(e) {
1029
+ return "<br>";
1030
+ }
1031
+ del({ tokens: e }) {
1032
+ return `<del>${this.parser.parseInline(e)}</del>`;
1033
+ }
1034
+ link({ href: e, title: t, text: n, tokens: s, autolink: r }) {
1035
+ let o = r ? R(n, true) : this.parser.parseInline(s), i = Y(e);
1036
+ if (i === null) return o;
1037
+ e = R(i, r);
1038
+ let l = '<a href="' + e + '"';
1039
+ return t && (l += ' title="' + R(t) + '"'), l += ">" + o + "</a>", l;
1040
+ }
1041
+ image({ href: e, title: t, text: n, tokens: s }) {
1042
+ s && (n = this.parser.parseInline(s, this.parser.textRenderer));
1043
+ let r = Y(e);
1044
+ if (r === null) return R(n);
1045
+ e = r;
1046
+ let o = `<img src="${R(e)}" alt="${R(n)}"`;
1047
+ return t && (o += ` title="${R(t)}"`), o += ">", o;
1048
+ }
1049
+ text(e) {
1050
+ return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : "escaped" in e && e.escaped ? e.text : R(e.text);
1051
+ }
1052
+ };
1053
+ var L = class {
1054
+ strong({ text: e }) {
1055
+ return e;
1056
+ }
1057
+ em({ text: e }) {
1058
+ return e;
1059
+ }
1060
+ codespan({ text: e }) {
1061
+ return e;
1062
+ }
1063
+ del({ text: e }) {
1064
+ return e;
1065
+ }
1066
+ html({ text: e }) {
1067
+ return e;
1068
+ }
1069
+ text({ text: e }) {
1070
+ return e;
1071
+ }
1072
+ link({ text: e }) {
1073
+ return "" + e;
1074
+ }
1075
+ image({ text: e }) {
1076
+ return "" + e;
1077
+ }
1078
+ br() {
1079
+ return "";
1080
+ }
1081
+ checkbox({ raw: e }) {
1082
+ return e;
1083
+ }
1084
+ };
1085
+ var b = class u2 {
1086
+ options;
1087
+ renderer;
1088
+ textRenderer;
1089
+ constructor(e) {
1090
+ this.options = e || T, this.options.renderer = this.options.renderer || new P(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new L();
1091
+ }
1092
+ static parse(e, t) {
1093
+ return new u2(t).parse(e);
1094
+ }
1095
+ static parseInline(e, t) {
1096
+ return new u2(t).parseInline(e);
1097
+ }
1098
+ parse(e) {
1099
+ this.renderer.parser = this;
1100
+ let t = "";
1101
+ for (let n = 0; n < e.length; n++) {
1102
+ let s = e[n];
1103
+ if (this.options.extensions?.renderers?.[s.type]) {
1104
+ let o = s, i = this.options.extensions.renderers[o.type].call({ parser: this }, o);
1105
+ if (i !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "checkbox", "html", "def", "paragraph", "text"].includes(o.type)) {
1106
+ t += i || "";
1107
+ continue;
1108
+ }
1109
+ }
1110
+ let r = s;
1111
+ switch (r.type) {
1112
+ case "space": {
1113
+ t += this.renderer.space(r);
1114
+ break;
1115
+ }
1116
+ case "hr": {
1117
+ t += this.renderer.hr(r);
1118
+ break;
1119
+ }
1120
+ case "heading": {
1121
+ t += this.renderer.heading(r);
1122
+ break;
1123
+ }
1124
+ case "code": {
1125
+ t += this.renderer.code(r);
1126
+ break;
1127
+ }
1128
+ case "table": {
1129
+ t += this.renderer.table(r);
1130
+ break;
1131
+ }
1132
+ case "blockquote": {
1133
+ t += this.renderer.blockquote(r);
1134
+ break;
1135
+ }
1136
+ case "list": {
1137
+ t += this.renderer.list(r);
1138
+ break;
1139
+ }
1140
+ case "checkbox": {
1141
+ t += this.renderer.checkbox(r);
1142
+ break;
1143
+ }
1144
+ case "html": {
1145
+ t += this.renderer.html(r);
1146
+ break;
1147
+ }
1148
+ case "def": {
1149
+ t += this.renderer.def(r);
1150
+ break;
1151
+ }
1152
+ case "paragraph": {
1153
+ t += this.renderer.paragraph(r);
1154
+ break;
1155
+ }
1156
+ case "text": {
1157
+ t += this.renderer.text(r);
1158
+ break;
1159
+ }
1160
+ default: {
1161
+ let o = 'Token with "' + r.type + '" type was not found.';
1162
+ if (this.options.silent) return console.error(o), "";
1163
+ throw new Error(o);
1164
+ }
1165
+ }
1166
+ }
1167
+ return t;
1168
+ }
1169
+ parseInline(e, t = this.renderer) {
1170
+ this.renderer.parser = this;
1171
+ let n = "";
1172
+ for (let s = 0; s < e.length; s++) {
1173
+ let r = e[s];
1174
+ if (this.options.extensions?.renderers?.[r.type]) {
1175
+ let i = this.options.extensions.renderers[r.type].call({ parser: this }, r);
1176
+ if (i !== false || !["escape", "html", "link", "image", "checkbox", "strong", "em", "codespan", "br", "del", "text"].includes(r.type)) {
1177
+ n += i || "";
1178
+ continue;
1179
+ }
1180
+ }
1181
+ let o = r;
1182
+ switch (o.type) {
1183
+ case "escape": {
1184
+ n += t.text(o);
1185
+ break;
1186
+ }
1187
+ case "html": {
1188
+ n += t.html(o);
1189
+ break;
1190
+ }
1191
+ case "link": {
1192
+ n += t.link(o);
1193
+ break;
1194
+ }
1195
+ case "image": {
1196
+ n += t.image(o);
1197
+ break;
1198
+ }
1199
+ case "checkbox": {
1200
+ n += t.checkbox(o);
1201
+ break;
1202
+ }
1203
+ case "strong": {
1204
+ n += t.strong(o);
1205
+ break;
1206
+ }
1207
+ case "em": {
1208
+ n += t.em(o);
1209
+ break;
1210
+ }
1211
+ case "codespan": {
1212
+ n += t.codespan(o);
1213
+ break;
1214
+ }
1215
+ case "br": {
1216
+ n += t.br(o);
1217
+ break;
1218
+ }
1219
+ case "del": {
1220
+ n += t.del(o);
1221
+ break;
1222
+ }
1223
+ case "text": {
1224
+ n += t.text(o);
1225
+ break;
1226
+ }
1227
+ default: {
1228
+ let i = 'Token with "' + o.type + '" type was not found.';
1229
+ if (this.options.silent) return console.error(i), "";
1230
+ throw new Error(i);
1231
+ }
1232
+ }
1233
+ }
1234
+ return n;
1235
+ }
1236
+ };
1237
+ var S = class {
1238
+ options;
1239
+ block;
1240
+ constructor(e) {
1241
+ this.options = e || T;
1242
+ }
1243
+ static passThroughHooks = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
1244
+ static passThroughHooksRespectAsync = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens"]);
1245
+ preprocess(e) {
1246
+ return e;
1247
+ }
1248
+ postprocess(e) {
1249
+ return e;
1250
+ }
1251
+ processAllTokens(e) {
1252
+ return e;
1253
+ }
1254
+ emStrongMask(e) {
1255
+ return e;
1256
+ }
1257
+ provideLexer(e = this.block) {
1258
+ return e ? x.lex : x.lexInline;
1259
+ }
1260
+ provideParser(e = this.block) {
1261
+ return e ? b.parse : b.parseInline;
1262
+ }
1263
+ };
1264
+ var Z = class {
1265
+ defaults = A();
1266
+ options = this.setOptions;
1267
+ parse = this.parseMarkdown(true);
1268
+ parseInline = this.parseMarkdown(false);
1269
+ Parser = b;
1270
+ Renderer = P;
1271
+ TextRenderer = L;
1272
+ Lexer = x;
1273
+ Tokenizer = y;
1274
+ Hooks = S;
1275
+ constructor(...e) {
1276
+ this.use(...e);
1277
+ }
1278
+ walkTokens(e, t) {
1279
+ let n = [];
1280
+ for (let s of e) switch (n = n.concat(t.call(this, s)), s.type) {
1281
+ case "table": {
1282
+ let r = s;
1283
+ for (let o of r.header) n = n.concat(this.walkTokens(o.tokens, t));
1284
+ for (let o of r.rows) for (let i of o) n = n.concat(this.walkTokens(i.tokens, t));
1285
+ break;
1286
+ }
1287
+ case "list": {
1288
+ let r = s;
1289
+ n = n.concat(this.walkTokens(r.items, t));
1290
+ break;
1291
+ }
1292
+ default: {
1293
+ let r = s;
1294
+ this.defaults.extensions?.childTokens?.[r.type] ? this.defaults.extensions.childTokens[r.type].forEach((o) => {
1295
+ let i = r[o].flat(1 / 0);
1296
+ n = n.concat(this.walkTokens(i, t));
1297
+ }) : r.tokens && (n = n.concat(this.walkTokens(r.tokens, t)));
1298
+ }
1299
+ }
1300
+ return n;
1301
+ }
1302
+ use(...e) {
1303
+ let t = this.defaults.extensions || { renderers: {}, childTokens: {} };
1304
+ return e.forEach((n) => {
1305
+ let s = { ...n };
1306
+ if (s.async = this.defaults.async || s.async || false, n.extensions && (n.extensions.forEach((r) => {
1307
+ if (!r.name) throw new Error("extension name required");
1308
+ if ("renderer" in r) {
1309
+ let o = t.renderers[r.name];
1310
+ o ? t.renderers[r.name] = function(...i) {
1311
+ let l = r.renderer.apply(this, i);
1312
+ return l === false && (l = o.apply(this, i)), l;
1313
+ } : t.renderers[r.name] = r.renderer;
1314
+ }
1315
+ if ("tokenizer" in r) {
1316
+ if (!r.level || r.level !== "block" && r.level !== "inline") throw new Error("extension level must be 'block' or 'inline'");
1317
+ let o = t[r.level];
1318
+ o ? o.unshift(r.tokenizer) : t[r.level] = [r.tokenizer], r.start && (r.level === "block" ? t.startBlock ? t.startBlock.push(r.start) : t.startBlock = [r.start] : r.level === "inline" && (t.startInline ? t.startInline.push(r.start) : t.startInline = [r.start]));
1319
+ }
1320
+ "childTokens" in r && r.childTokens && (t.childTokens[r.name] = r.childTokens);
1321
+ }), s.extensions = t), n.renderer) {
1322
+ let r = this.defaults.renderer || new P(this.defaults);
1323
+ for (let o in n.renderer) {
1324
+ if (!(o in r)) throw new Error(`renderer '${o}' does not exist`);
1325
+ if (["options", "parser"].includes(o)) continue;
1326
+ let i = o, l = n.renderer[i], a = r[i];
1327
+ r[i] = (...p) => {
1328
+ let c = l.apply(r, p);
1329
+ return c === false && (c = a.apply(r, p)), c || "";
1330
+ };
1331
+ }
1332
+ s.renderer = r;
1333
+ }
1334
+ if (n.tokenizer) {
1335
+ let r = this.defaults.tokenizer || new y(this.defaults);
1336
+ for (let o in n.tokenizer) {
1337
+ if (!(o in r)) throw new Error(`tokenizer '${o}' does not exist`);
1338
+ if (["options", "rules", "lexer"].includes(o)) continue;
1339
+ let i = o, l = n.tokenizer[i], a = r[i];
1340
+ r[i] = (...p) => {
1341
+ let c = l.apply(r, p);
1342
+ return c === false && (c = a.apply(r, p)), c;
1343
+ };
1344
+ }
1345
+ s.tokenizer = r;
1346
+ }
1347
+ if (n.hooks) {
1348
+ let r = this.defaults.hooks || new S();
1349
+ for (let o in n.hooks) {
1350
+ if (!(o in r)) throw new Error(`hook '${o}' does not exist`);
1351
+ if (["options", "block"].includes(o)) continue;
1352
+ let i = o, l = n.hooks[i], a = r[i];
1353
+ S.passThroughHooks.has(o) ? r[i] = (p) => {
1354
+ if (this.defaults.async && S.passThroughHooksRespectAsync.has(o)) return (async () => {
1355
+ let h = await l.call(r, p);
1356
+ return a.call(r, h);
1357
+ })();
1358
+ let c = l.call(r, p);
1359
+ return a.call(r, c);
1360
+ } : r[i] = (...p) => {
1361
+ if (this.defaults.async) return (async () => {
1362
+ let h = await l.apply(r, p);
1363
+ return h === false && (h = await a.apply(r, p)), h;
1364
+ })();
1365
+ let c = l.apply(r, p);
1366
+ return c === false && (c = a.apply(r, p)), c;
1367
+ };
1368
+ }
1369
+ s.hooks = r;
1370
+ }
1371
+ if (n.walkTokens) {
1372
+ let r = this.defaults.walkTokens, o = n.walkTokens;
1373
+ s.walkTokens = function(i) {
1374
+ let l = [];
1375
+ return l.push(o.call(this, i)), r && (l = l.concat(r.call(this, i))), l;
1376
+ };
1377
+ }
1378
+ this.defaults = { ...this.defaults, ...s };
1379
+ }), this;
1380
+ }
1381
+ setOptions(e) {
1382
+ return this.defaults = { ...this.defaults, ...e }, this;
1383
+ }
1384
+ lexer(e, t) {
1385
+ return x.lex(e, t ?? this.defaults);
1386
+ }
1387
+ parser(e, t) {
1388
+ return b.parse(e, t ?? this.defaults);
1389
+ }
1390
+ parseMarkdown(e) {
1391
+ return (n, s) => {
1392
+ let r = { ...s }, o = { ...this.defaults, ...r }, i = this.onError(!!o.silent, !!o.async);
1393
+ if (this.defaults.async === true && r.async === false) return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
1394
+ if (typeof n > "u" || n === null) return i(new Error("marked(): input parameter is undefined or null"));
1395
+ if (typeof n != "string") return i(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
1396
+ if (o.hooks && (o.hooks.options = o, o.hooks.block = e), o.async) return (async () => {
1397
+ let l = o.hooks ? await o.hooks.preprocess(n) : n, p = await (o.hooks ? await o.hooks.provideLexer(e) : e ? x.lex : x.lexInline)(l, o), c = o.hooks ? await o.hooks.processAllTokens(p) : p;
1398
+ o.walkTokens && await Promise.all(this.walkTokens(c, o.walkTokens));
1399
+ let d = await (o.hooks ? await o.hooks.provideParser(e) : e ? b.parse : b.parseInline)(c, o);
1400
+ return o.hooks ? await o.hooks.postprocess(d) : d;
1401
+ })().catch(i);
1402
+ try {
1403
+ o.hooks && (n = o.hooks.preprocess(n));
1404
+ let a = (o.hooks ? o.hooks.provideLexer(e) : e ? x.lex : x.lexInline)(n, o);
1405
+ o.hooks && (a = o.hooks.processAllTokens(a)), o.walkTokens && this.walkTokens(a, o.walkTokens);
1406
+ let c = (o.hooks ? o.hooks.provideParser(e) : e ? b.parse : b.parseInline)(a, o);
1407
+ return o.hooks && (c = o.hooks.postprocess(c)), c;
1408
+ } catch (l) {
1409
+ return i(l);
1410
+ }
1411
+ };
1412
+ }
1413
+ onError(e, t) {
1414
+ return (n) => {
1415
+ if (n.message += `
1416
+ Please report this to https://github.com/markedjs/marked.`, e) {
1417
+ let s = "<p>An error occurred:</p><pre>" + R(n.message + "", true) + "</pre>";
1418
+ return t ? Promise.resolve(s) : s;
1419
+ }
1420
+ if (t) return Promise.reject(n);
1421
+ throw n;
1422
+ };
1423
+ }
1424
+ };
1425
+ var M = new Z();
1426
+ function f(u3, e) {
1427
+ return M.parse(u3, e);
1428
+ }
1429
+ f.options = f.setOptions = function(u3) {
1430
+ return M.setOptions(u3), f.defaults = M.defaults, j(f.defaults), f;
1431
+ };
1432
+ f.getDefaults = A;
1433
+ f.defaults = T;
1434
+ function gt(...u3) {
1435
+ return M.use(...u3), f.defaults = M.defaults, j(f.defaults), f;
1436
+ }
1437
+ f.use = gt;
1438
+ f.walkTokens = function(u3, e) {
1439
+ return M.walkTokens(u3, e);
1440
+ };
1441
+ f.parseInline = M.parseInline;
1442
+ f.Parser = b;
1443
+ f.parser = b.parse;
1444
+ f.Renderer = P;
1445
+ f.TextRenderer = L;
1446
+ f.Lexer = x;
1447
+ f.lexer = x.lex;
1448
+ f.Tokenizer = y;
1449
+ f.Hooks = S;
1450
+ f.parse = f;
1451
+ var rn = f.options;
1452
+ var sn = f.setOptions;
1453
+ var on = f.walkTokens;
1454
+ var an = f.parseInline;
1455
+ var un = b.parse;
1456
+ var pn = x.lex;
1457
+
1458
+ // src/client/markdown.ts
1459
+ var fallbackOrigin = "http://localhost";
1460
+ var safeLinkProtocols = /* @__PURE__ */ new Set(["http:", "https:", "mailto:"]);
1461
+ var safeImageProtocols = /* @__PURE__ */ new Set(["http:", "https:"]);
1462
+ function escapeHtml(value) {
1463
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1464
+ }
1465
+ function currentOrigin() {
1466
+ return typeof window === "undefined" ? fallbackOrigin : window.location.origin;
1467
+ }
1468
+ function normalizeUrl(value, origin) {
1469
+ try {
1470
+ const base = new URL(origin);
1471
+ const url = new URL(value, base);
1472
+ return {
1473
+ href: url.href,
1474
+ protocol: url.protocol.toLowerCase(),
1475
+ sameOrigin: url.origin === base.origin
1476
+ };
1477
+ } catch {
1478
+ return void 0;
1479
+ }
1480
+ }
1481
+ function titleAttribute(title) {
1482
+ return title === null || title === void 0 ? "" : ` title="${escapeHtml(title)}"`;
1483
+ }
1484
+ function renderLink(token, origin, parseInline) {
1485
+ const label = parseInline(token.tokens);
1486
+ const url = normalizeUrl(token.href, origin);
1487
+ if (!url || !safeLinkProtocols.has(url.protocol)) {
1488
+ return `<span class="markdown-unsafe-link">${label}</span>`;
1489
+ }
1490
+ return `<a href="${escapeHtml(url.href)}"${titleAttribute(token.title)} target="_blank" rel="noopener noreferrer">${label}</a>`;
1491
+ }
1492
+ function renderImage(token, origin) {
1493
+ const alt = token.text || "image";
1494
+ const escapedAlt = escapeHtml(alt);
1495
+ const url = normalizeUrl(token.href, origin);
1496
+ if (!url || !safeImageProtocols.has(url.protocol)) {
1497
+ return `<span class="markdown-image-unavailable">${escapedAlt}</span>`;
1498
+ }
1499
+ if (!url.sameOrigin) {
1500
+ return `<a class="markdown-external-image" href="${escapeHtml(url.href)}"${titleAttribute(token.title)} target="_blank" rel="noopener noreferrer">Open image: ${escapedAlt}</a>`;
1501
+ }
1502
+ return `<img class="markdown-image" src="${escapeHtml(url.href)}" alt="${escapedAlt}"${titleAttribute(token.title)}>`;
1503
+ }
1504
+ function renderMarkdown(source, origin = currentOrigin()) {
1505
+ try {
1506
+ const parser = new Z({
1507
+ async: false,
1508
+ gfm: true,
1509
+ renderer: {
1510
+ html(token) {
1511
+ return escapeHtml(token.text);
1512
+ },
1513
+ link(token) {
1514
+ return renderLink(token, origin, (tokens) => this.parser.parseInline(tokens));
1515
+ },
1516
+ image(token) {
1517
+ return renderImage(token, origin);
1518
+ }
1519
+ }
1520
+ });
1521
+ return parser.parse(source, { async: false });
1522
+ } catch {
1523
+ return `<pre class="markdown-fallback">${escapeHtml(source)}</pre>`;
1524
+ }
1525
+ }
1526
+
1527
+ // src/client/message-queue.ts
1528
+ function copyMessageQueue(queue) {
1529
+ return {
1530
+ steering: [...queue?.steering ?? []],
1531
+ followUp: [...queue?.followUp ?? []]
1532
+ };
1533
+ }
1534
+ function messageQueueFromEvent(event) {
1535
+ return {
1536
+ steering: Array.isArray(event.steering) ? event.steering.filter((message) => typeof message === "string") : [],
1537
+ followUp: Array.isArray(event.followUp) ? event.followUp.filter((message) => typeof message === "string") : []
1538
+ };
1539
+ }
1540
+ function removedSteeringPrefix(previous, next) {
1541
+ const removedCount = previous.steering.length - next.steering.length;
1542
+ if (removedCount <= 0) {
1543
+ return [];
1544
+ }
1545
+ const unchangedRemainder = next.steering.every(
1546
+ (message, index) => previous.steering[index + removedCount] === message
1547
+ );
1548
+ return unchangedRemainder ? previous.steering.slice(0, removedCount) : [];
1549
+ }
1550
+ function steeringQueueGrew(previous, next) {
1551
+ if (next.steering.length <= previous.steering.length) {
1552
+ return false;
1553
+ }
1554
+ return previous.steering.every((message, index) => next.steering[index] === message);
1555
+ }
1556
+ function reconcileMessageQueue(previous, next, discardRemoved = false) {
1557
+ return {
1558
+ queue: copyMessageQueue(next),
1559
+ dequeuedSteering: discardRemoved ? [] : removedSteeringPrefix(previous, next)
1560
+ };
1561
+ }
1562
+ function withoutSteeringMessage(queue, index, expectedMessage) {
1563
+ if (!Number.isSafeInteger(index) || index < 0 || queue.steering[index] !== expectedMessage) {
1564
+ return void 0;
1565
+ }
1566
+ const next = copyMessageQueue(queue);
1567
+ next.steering.splice(index, 1);
1568
+ return next;
1569
+ }
1570
+
1571
+ // src/client/slash-completion.ts
1572
+ function fuzzyMatch(query, text) {
1573
+ const queryLower = query.toLowerCase();
1574
+ const textLower = text.toLowerCase();
1575
+ const matchQuery = (normalizedQuery) => {
1576
+ if (normalizedQuery.length === 0) {
1577
+ return { matches: true, score: 0 };
1578
+ }
1579
+ if (normalizedQuery.length > textLower.length) {
1580
+ return { matches: false, score: 0 };
1581
+ }
1582
+ let queryIndex = 0;
1583
+ let score = 0;
1584
+ let lastMatchIndex = -1;
1585
+ let consecutiveMatches = 0;
1586
+ for (let index = 0; index < textLower.length && queryIndex < normalizedQuery.length; index += 1) {
1587
+ if (textLower[index] !== normalizedQuery[queryIndex]) {
1588
+ continue;
1589
+ }
1590
+ const isWordBoundary = index === 0 || /[\s\-_./:]/.test(textLower[index - 1] ?? "");
1591
+ if (lastMatchIndex === index - 1) {
1592
+ consecutiveMatches += 1;
1593
+ score -= consecutiveMatches * 5;
1594
+ } else {
1595
+ consecutiveMatches = 0;
1596
+ if (lastMatchIndex >= 0) {
1597
+ score += (index - lastMatchIndex - 1) * 2;
1598
+ }
1599
+ }
1600
+ if (isWordBoundary) {
1601
+ score -= 10;
1602
+ }
1603
+ score += index * 0.1;
1604
+ lastMatchIndex = index;
1605
+ queryIndex += 1;
1606
+ }
1607
+ if (queryIndex < normalizedQuery.length) {
1608
+ return { matches: false, score: 0 };
1609
+ }
1610
+ if (normalizedQuery === textLower) {
1611
+ score -= 100;
1612
+ }
1613
+ return { matches: true, score };
1614
+ };
1615
+ const primaryMatch = matchQuery(queryLower);
1616
+ if (primaryMatch.matches) {
1617
+ return primaryMatch;
1618
+ }
1619
+ const alphaNumericMatch = queryLower.match(/^(?<letters>[a-z]+)(?<digits>[0-9]+)$/);
1620
+ const numericAlphaMatch = queryLower.match(/^(?<digits>[0-9]+)(?<letters>[a-z]+)$/);
1621
+ const swappedQuery = alphaNumericMatch ? `${alphaNumericMatch.groups?.digits ?? ""}${alphaNumericMatch.groups?.letters ?? ""}` : numericAlphaMatch ? `${numericAlphaMatch.groups?.letters ?? ""}${numericAlphaMatch.groups?.digits ?? ""}` : "";
1622
+ if (!swappedQuery) {
1623
+ return primaryMatch;
1624
+ }
1625
+ const swappedMatch = matchQuery(swappedQuery);
1626
+ return swappedMatch.matches ? { matches: true, score: swappedMatch.score + 5 } : primaryMatch;
1627
+ }
1628
+ function fuzzyFilter(items, query, getText) {
1629
+ if (!query.trim()) {
1630
+ return [...items];
1631
+ }
1632
+ const tokens = query.trim().split(/[\s/]+/).filter((token) => token.length > 0);
1633
+ if (tokens.length === 0) {
1634
+ return [...items];
1635
+ }
1636
+ const results = [];
1637
+ for (const item of items) {
1638
+ let totalScore = 0;
1639
+ let allMatch = true;
1640
+ for (const token of tokens) {
1641
+ const match = fuzzyMatch(token, getText(item));
1642
+ if (!match.matches) {
1643
+ allMatch = false;
1644
+ break;
1645
+ }
1646
+ totalScore += match.score;
1647
+ }
1648
+ if (allMatch) {
1649
+ results.push({ item, totalScore });
1650
+ }
1651
+ }
1652
+ results.sort((left, right) => left.totalScore - right.totalScore);
1653
+ return results.map(({ item }) => item);
1654
+ }
1655
+ function slashCommandQuery(value) {
1656
+ return /^\/(\S*)$/.exec(value)?.[1] ?? null;
1657
+ }
1658
+ function createSlashCompletionState(commands, value, selectedName) {
1659
+ const query = slashCommandQuery(value);
1660
+ if (query === null) {
1661
+ return null;
1662
+ }
1663
+ const matches = fuzzyFilter(commands, query, (command) => command.name);
1664
+ if (matches.length === 0) {
1665
+ return null;
1666
+ }
1667
+ const previousIndex = selectedName === void 0 ? -1 : matches.findIndex((command) => command.name === selectedName);
1668
+ return {
1669
+ query,
1670
+ matches,
1671
+ selectedIndex: previousIndex >= 0 ? previousIndex : 0
1672
+ };
1673
+ }
1674
+ function moveSlashCompletionSelection(state, offset) {
1675
+ const count = state.matches.length;
1676
+ const selectedIndex = ((state.selectedIndex + offset) % count + count) % count;
1677
+ return { ...state, selectedIndex };
1678
+ }
1679
+ function getSlashCompletionWindow(state, maxVisible = 5) {
1680
+ const size = Math.max(1, Math.floor(maxVisible));
1681
+ const startIndex = Math.max(0, Math.min(state.matches.length - size, state.selectedIndex - Math.floor(size / 2)));
1682
+ return {
1683
+ startIndex,
1684
+ items: state.matches.slice(startIndex, startIndex + size)
1685
+ };
1686
+ }
1687
+ function completeSlashCommand(command) {
1688
+ return `/${command.name} `;
1689
+ }
1690
+
1691
+ // src/client/shared.ts
1692
+ function requiredElement(selector, root = document) {
1693
+ const element = root.querySelector(selector);
1694
+ if (!element) {
1695
+ throw new Error(`Missing required element: ${selector}`);
1696
+ }
1697
+ return element;
1698
+ }
1699
+ function textElement(tag, className, text) {
1700
+ const element = document.createElement(tag);
1701
+ element.className = className;
1702
+ element.textContent = text;
1703
+ return element;
1704
+ }
1705
+ function readableError(error) {
1706
+ return error instanceof Error ? error.message : String(error);
1707
+ }
1708
+ async function api(path, options) {
1709
+ const response = await fetch(path, options);
1710
+ const body = await response.json().catch(() => void 0);
1711
+ if (!response.ok) {
1712
+ throw new Error(body?.error?.message ?? `Request failed (${response.status})`);
1713
+ }
1714
+ return body;
1715
+ }
1716
+ function sessionPath(id) {
1717
+ return `/sessions/${encodeURIComponent(id)}`;
1718
+ }
1719
+
1720
+ // src/client/transcript-activity.ts
1721
+ var MAX_ACTIVITY_PREVIEW_CHARS = 120;
1722
+ function boundedText(value, maximum) {
1723
+ const characters = Array.from(value);
1724
+ if (characters.length <= maximum) {
1725
+ return value;
1726
+ }
1727
+ const prefix = characters.slice(0, maximum - 1).join("").trimEnd();
1728
+ return `${prefix}\u2026`;
1729
+ }
1730
+ function activityPreview(value) {
1731
+ const plainText = value.replace(/\[([^\]]+)\]\([^\s)]+\)/gu, "$1").replace(/`([^`]+)`/gu, "$1").replace(/[*~]{1,3}/gu, "").replace(/^#{1,6}\s+/gmu, "");
1732
+ const normalized = plainText.replace(/\s+/gu, " ").trim();
1733
+ const sentenceEnd = /[.!?。!?](?=\s|$)/u.exec(normalized);
1734
+ const sentence = sentenceEnd ? normalized.slice(0, sentenceEnd.index + sentenceEnd[0].length) : normalized;
1735
+ return boundedText(sentence, MAX_ACTIVITY_PREVIEW_CHARS);
1736
+ }
1737
+ function toolActionLabel(toolName, completed = false) {
1738
+ const name = typeof toolName === "string" && toolName.trim() ? toolName.trim() : "tool";
1739
+ return `Tool \xB7 ${name}${completed ? " \xB7 done" : ""}`;
1740
+ }
1741
+ function partitionAssistantContent(content) {
1742
+ if (!Array.isArray(content)) {
1743
+ return {
1744
+ activity: [],
1745
+ responseContent: content,
1746
+ hasResponse: content !== void 0 && content !== ""
1747
+ };
1748
+ }
1749
+ const activity = [];
1750
+ const response = [];
1751
+ for (const part of content) {
1752
+ if (!part || typeof part !== "object") {
1753
+ response.push(part);
1754
+ continue;
1755
+ }
1756
+ const block = part;
1757
+ if (block.type === "thinking") {
1758
+ activity.push({ kind: "thinking", text: typeof block.thinking === "string" ? block.thinking : "" });
1759
+ continue;
1760
+ }
1761
+ if (block.type === "toolCall") {
1762
+ activity.push({
1763
+ kind: "toolCall",
1764
+ name: typeof block.name === "string" && block.name.trim() ? block.name : "tool",
1765
+ arguments: block.arguments
1766
+ });
1767
+ continue;
1768
+ }
1769
+ response.push(part);
1770
+ }
1771
+ return { activity, responseContent: response, hasResponse: response.length > 0 };
1772
+ }
1773
+ function appendActivityItem(group, item) {
1774
+ group.items.push(item);
1775
+ if (item.kind === "thinking") {
1776
+ const preview = activityPreview(item.text);
1777
+ if (preview) {
1778
+ group.preview = preview;
1779
+ }
1780
+ } else if (item.kind === "toolCall") {
1781
+ group.lastAction = toolActionLabel(item.name);
1782
+ } else {
1783
+ group.lastAction = toolActionLabel(item.message.toolName, true);
1784
+ }
1785
+ }
1786
+ function groupTranscriptActivity(entries) {
1787
+ const grouped = [];
1788
+ let activity;
1789
+ const ensureActivity = () => {
1790
+ if (activity) {
1791
+ return activity;
1792
+ }
1793
+ activity = { kind: "activity", items: [] };
1794
+ grouped.push(activity);
1795
+ return activity;
1796
+ };
1797
+ for (const entry of entries) {
1798
+ if (entry.kind !== "message") {
1799
+ grouped.push(entry);
1800
+ continue;
1801
+ }
1802
+ const { message } = entry;
1803
+ if (message.role === "user") {
1804
+ activity = void 0;
1805
+ grouped.push(entry);
1806
+ continue;
1807
+ }
1808
+ if (message.role === "assistant") {
1809
+ const partitioned = partitionAssistantContent(message.content);
1810
+ for (const item of partitioned.activity) {
1811
+ appendActivityItem(ensureActivity(), item);
1812
+ }
1813
+ if (message.stopReason === "aborted") {
1814
+ ensureActivity().outcome = "aborted";
1815
+ }
1816
+ if (partitioned.hasResponse) {
1817
+ grouped.push({
1818
+ ...entry,
1819
+ message: { ...message, content: partitioned.responseContent }
1820
+ });
1821
+ }
1822
+ continue;
1823
+ }
1824
+ if (message.role === "toolResult" || message.role === "live-tool") {
1825
+ appendActivityItem(ensureActivity(), { kind: "toolResult", message });
1826
+ continue;
1827
+ }
1828
+ grouped.push(entry);
1829
+ }
1830
+ return grouped;
1831
+ }
1832
+
1833
+ // src/client/usage-format.ts
1834
+ var fullNumberFormatter = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
1835
+ function formatCompactTokens(count) {
1836
+ if (count < 1e3) {
1837
+ return count.toString();
1838
+ }
1839
+ if (count < 1e4) {
1840
+ return `${(count / 1e3).toFixed(1)}k`;
1841
+ }
1842
+ if (count < 1e6) {
1843
+ return `${Math.round(count / 1e3)}k`;
1844
+ }
1845
+ if (count < 1e7) {
1846
+ return `${(count / 1e6).toFixed(1)}M`;
1847
+ }
1848
+ return `${Math.round(count / 1e6)}M`;
1849
+ }
1850
+ function fullTokens(count) {
1851
+ return `${fullNumberFormatter.format(count)} tokens`;
1852
+ }
1853
+ function punctuate(parts, fallback) {
1854
+ return `${parts.length > 0 ? parts.join("; ") : fallback}.`;
1855
+ }
1856
+ function formatSessionUsage(usage, autoCompactionEnabled) {
1857
+ if (!usage) {
1858
+ return {
1859
+ tokenLines: ["Loading\u2026"],
1860
+ tokenAccessibleText: "Token usage is loading.",
1861
+ context: {
1862
+ state: "loading",
1863
+ percentageText: "Loading\u2026",
1864
+ capacityText: null,
1865
+ meterPercent: null,
1866
+ autoCompactionEnabled: false,
1867
+ accessibleText: "Context usage is loading."
1868
+ }
1869
+ };
1870
+ }
1871
+ const tokenLines = [];
1872
+ const tokenAccessibleParts = [];
1873
+ const inputOutputParts = [];
1874
+ const cacheParts = [];
1875
+ if (usage.tokens.input) {
1876
+ inputOutputParts.push(`In ${formatCompactTokens(usage.tokens.input)}`);
1877
+ tokenAccessibleParts.push(`Input: ${fullTokens(usage.tokens.input)}`);
1878
+ }
1879
+ if (usage.tokens.output) {
1880
+ inputOutputParts.push(`Out ${formatCompactTokens(usage.tokens.output)}`);
1881
+ tokenAccessibleParts.push(`Output: ${fullTokens(usage.tokens.output)}`);
1882
+ }
1883
+ if (usage.tokens.cacheRead) {
1884
+ cacheParts.push(`Cache read ${formatCompactTokens(usage.tokens.cacheRead)}`);
1885
+ tokenAccessibleParts.push(`Cache read: ${fullTokens(usage.tokens.cacheRead)}`);
1886
+ }
1887
+ if (usage.tokens.cacheWrite) {
1888
+ cacheParts.push(`write ${formatCompactTokens(usage.tokens.cacheWrite)}`);
1889
+ tokenAccessibleParts.push(`Cache write: ${fullTokens(usage.tokens.cacheWrite)}`);
1890
+ }
1891
+ if (inputOutputParts.length > 0) {
1892
+ tokenLines.push(inputOutputParts.join(" \xB7 "));
1893
+ }
1894
+ if (cacheParts.length > 0) {
1895
+ tokenLines.push(cacheParts.join(" \xB7 "));
1896
+ }
1897
+ const tokenAccessibleText = punctuate(tokenAccessibleParts, "No token usage yet");
1898
+ if (!usage.context) {
1899
+ return {
1900
+ tokenLines,
1901
+ tokenAccessibleText,
1902
+ context: {
1903
+ state: "unavailable",
1904
+ percentageText: "Unavailable",
1905
+ capacityText: null,
1906
+ meterPercent: null,
1907
+ autoCompactionEnabled,
1908
+ accessibleText: autoCompactionEnabled ? "Context usage unavailable; auto-compaction enabled." : "Context usage unavailable."
1909
+ }
1910
+ };
1911
+ }
1912
+ const contextWindow = formatCompactTokens(usage.context.contextWindow);
1913
+ if (usage.context.tokens === null || usage.context.percent === null) {
1914
+ return {
1915
+ tokenLines,
1916
+ tokenAccessibleText,
1917
+ context: {
1918
+ state: "unknown",
1919
+ percentageText: "\u2014",
1920
+ capacityText: `? / ${contextWindow} tokens`,
1921
+ meterPercent: null,
1922
+ autoCompactionEnabled,
1923
+ accessibleText: `Context: unknown of ${fullTokens(usage.context.contextWindow)} until the next model response; auto-compaction ${autoCompactionEnabled ? "enabled" : "disabled"}.`
1924
+ }
1925
+ };
1926
+ }
1927
+ const roundedPercent = Math.round(usage.context.percent);
1928
+ return {
1929
+ tokenLines,
1930
+ tokenAccessibleText,
1931
+ context: {
1932
+ state: "known",
1933
+ percentageText: `${roundedPercent}% used`,
1934
+ capacityText: `${formatCompactTokens(usage.context.tokens)} / ${contextWindow} tokens`,
1935
+ meterPercent: Math.min(100, Math.max(0, usage.context.percent)),
1936
+ autoCompactionEnabled,
1937
+ accessibleText: `Context: ${fullTokens(usage.context.tokens)} of ${fullTokens(usage.context.contextWindow)} (${roundedPercent}%); auto-compaction ${autoCompactionEnabled ? "enabled" : "disabled"}.`
1938
+ }
1939
+ };
1940
+ }
1941
+
1942
+ // src/client/workspace-browser.ts
1943
+ function relativePathWithin(root, candidate) {
1944
+ const separator = root.includes("\\") && !root.includes("/") ? "\\" : "/";
1945
+ const normalizedRoot = root.replaceAll("\\", "/").replace(/\/+$/, "") || "/";
1946
+ const normalizedCandidate = candidate.replaceAll("\\", "/").replace(/\/+$/, "") || "/";
1947
+ const caseInsensitive = /^[A-Za-z]:/.test(normalizedRoot);
1948
+ const comparableRoot = caseInsensitive ? normalizedRoot.toLocaleLowerCase() : normalizedRoot;
1949
+ const comparableCandidate = caseInsensitive ? normalizedCandidate.toLocaleLowerCase() : normalizedCandidate;
1950
+ if (comparableCandidate === comparableRoot) {
1951
+ return ".";
1952
+ }
1953
+ const rootPrefix = comparableRoot === "/" ? "/" : `${comparableRoot}/`;
1954
+ if (!comparableCandidate.startsWith(rootPrefix)) {
1955
+ return null;
1956
+ }
1957
+ return normalizedCandidate.slice(rootPrefix.length).replaceAll("/", separator);
1958
+ }
1959
+
1960
+ // src/client/session.ts
1961
+ var elements = {
1962
+ abort: requiredElement("[data-abort]"),
1963
+ composer: requiredElement("[data-composer]"),
1964
+ connection: requiredElement("[data-connection]"),
1965
+ createSession: requiredElement("[data-create-session]"),
1966
+ extensionPrompt: requiredElement("[data-extension-prompt]"),
1967
+ extensionStatusItem: requiredElement("[data-extension-status-item]"),
1968
+ extensionStatuses: requiredElement("[data-extension-statuses]"),
1969
+ extensionWidgetsAbove: requiredElement("[data-extension-widgets-above]"),
1970
+ extensionWidgetsBelow: requiredElement("[data-extension-widgets-below]"),
1971
+ prompt: requiredElement("[data-prompt]"),
1972
+ send: requiredElement("[data-send]"),
1973
+ sessionContext: requiredElement(".session-context"),
1974
+ sessionContextToggle: requiredElement("[data-session-context-toggle]"),
1975
+ sessionContextUsage: requiredElement("[data-session-context-usage]"),
1976
+ sessionModel: requiredElement("[data-session-model]"),
1977
+ sessionTokens: requiredElement("[data-session-tokens]"),
1978
+ sessionWorkspaceRepository: requiredElement("[data-session-workspace-repository]"),
1979
+ sessionWorkspaceRepositoryPath: requiredElement("[data-session-workspace-repository-path]"),
1980
+ sessionWorkspaceState: requiredElement("[data-session-workspace-state]"),
1981
+ sessionWorkspaceWorkingDirectory: requiredElement("[data-session-workspace-working-directory]"),
1982
+ sessionWorkspaceWorkingDirectoryPath: requiredElement("[data-session-workspace-working-directory-path]"),
1983
+ sessionWorkspaceWorktree: requiredElement("[data-session-workspace-worktree]"),
1984
+ sessionWorkspaceWorktreePath: requiredElement("[data-session-workspace-worktree-path]"),
1985
+ slashCompletion: requiredElement("[data-slash-completion]"),
1986
+ sessionTitle: requiredElement("[data-session-title]"),
1987
+ transcript: requiredElement("[data-transcript]")
1988
+ };
1989
+ var currentSession;
1990
+ var currentRuntime = null;
1991
+ var currentSessionId;
1992
+ var liveMessage;
1993
+ var liveActivity;
1994
+ var streamBlocks = /* @__PURE__ */ new Map();
1995
+ var markdownRenderFrame;
1996
+ var pendingMarkdownBlocks = /* @__PURE__ */ new Set();
1997
+ var sending = false;
1998
+ var renaming = false;
1999
+ var extensionUI = { pending: [], statuses: [], widgets: [] };
2000
+ var renderedExtensionRequestId;
2001
+ var slashCompletion = null;
2002
+ var dismissedSlashCompletionValue;
2003
+ var reconcileSequence = 0;
2004
+ var optimisticSubmission;
2005
+ var submittedTurnAnchor;
2006
+ var submittedTurnRunwayFrame;
2007
+ var dequeuedSteering = [];
2008
+ var discardingQueue = false;
2009
+ var liveTools = /* @__PURE__ */ new Map();
2010
+ var SLASH_COMPLETION_MAX_VISIBLE = 5;
2011
+ function currentNativeName() {
2012
+ return currentRuntime?.sessionName?.trim() || currentSession?.name?.trim() || void 0;
2013
+ }
2014
+ function updateSessionHeading() {
2015
+ if (!currentSessionId) {
2016
+ return;
2017
+ }
2018
+ const title = displaySessionTitle({
2019
+ name: currentNativeName(),
2020
+ firstMessage: currentSession?.firstMessage
2021
+ });
2022
+ const renameLabel = `Rename session title: ${title}`;
2023
+ elements.sessionTitle.textContent = title;
2024
+ elements.sessionTitle.title = renameLabel;
2025
+ elements.sessionTitle.setAttribute("aria-label", renameLabel);
2026
+ document.title = `${title} \xB7 Pi`;
2027
+ }
2028
+ function applyCurrentSessionName(name) {
2029
+ if (currentRuntime) {
2030
+ if (name) {
2031
+ currentRuntime.sessionName = name;
2032
+ } else {
2033
+ delete currentRuntime.sessionName;
2034
+ }
2035
+ }
2036
+ if (currentSession) {
2037
+ if (name) {
2038
+ currentSession.name = name;
2039
+ } else {
2040
+ delete currentSession.name;
2041
+ }
2042
+ }
2043
+ updateSessionHeading();
2044
+ }
2045
+ function setConnection(label, state) {
2046
+ elements.connection.textContent = label;
2047
+ elements.connection.dataset.state = state;
2048
+ }
2049
+ function setSessionContextCollapsed(collapsed) {
2050
+ const label = `${collapsed ? "Expand" : "Collapse"} session context`;
2051
+ elements.sessionContext.classList.toggle("is-collapsed", collapsed);
2052
+ elements.sessionContextToggle.setAttribute("aria-expanded", String(!collapsed));
2053
+ elements.sessionContextToggle.setAttribute("aria-label", label);
2054
+ elements.sessionContextToggle.title = label;
2055
+ }
2056
+ function resizePrompt() {
2057
+ elements.prompt.style.height = "auto";
2058
+ elements.prompt.style.overflowY = "hidden";
2059
+ const styles = getComputedStyle(elements.prompt);
2060
+ const borderHeight = Number.parseFloat(styles.borderTopWidth) + Number.parseFloat(styles.borderBottomWidth);
2061
+ const naturalHeight = elements.prompt.scrollHeight + borderHeight;
2062
+ elements.prompt.style.height = `${naturalHeight}px`;
2063
+ const renderedHeight = elements.prompt.getBoundingClientRect().height;
2064
+ elements.prompt.style.overflowY = naturalHeight > renderedHeight + 0.5 ? "auto" : "hidden";
2065
+ }
2066
+ function closeSlashCompletion(dismiss = false) {
2067
+ if (dismiss) {
2068
+ dismissedSlashCompletionValue = elements.prompt.value;
2069
+ }
2070
+ slashCompletion = null;
2071
+ elements.slashCompletion.hidden = true;
2072
+ elements.slashCompletion.replaceChildren();
2073
+ elements.prompt.setAttribute("aria-expanded", "false");
2074
+ elements.prompt.removeAttribute("aria-activedescendant");
2075
+ }
2076
+ function applySelectedSlashCompletion(submit) {
2077
+ const command = slashCompletion?.matches[slashCompletion.selectedIndex];
2078
+ if (!command) {
2079
+ return;
2080
+ }
2081
+ setPromptValue(completeSlashCommand(command));
2082
+ elements.prompt.setSelectionRange(elements.prompt.value.length, elements.prompt.value.length);
2083
+ elements.prompt.focus();
2084
+ if (submit) {
2085
+ void sendMessage();
2086
+ }
2087
+ }
2088
+ function renderSlashCompletion(resetSelection = false) {
2089
+ if (elements.prompt.disabled || dismissedSlashCompletionValue === elements.prompt.value) {
2090
+ closeSlashCompletion();
2091
+ return;
2092
+ }
2093
+ const selectedName = resetSelection ? void 0 : slashCompletion?.matches[slashCompletion.selectedIndex]?.name;
2094
+ const nextState = createSlashCompletionState(currentRuntime?.commands ?? [], elements.prompt.value, selectedName);
2095
+ if (!nextState) {
2096
+ closeSlashCompletion();
2097
+ return;
2098
+ }
2099
+ slashCompletion = nextState;
2100
+ const visible = getSlashCompletionWindow(nextState, SLASH_COMPLETION_MAX_VISIBLE);
2101
+ const options = visible.items.map((command, visibleIndex) => {
2102
+ const index = visible.startIndex + visibleIndex;
2103
+ const selected = index === nextState.selectedIndex;
2104
+ const option = document.createElement("button");
2105
+ option.type = "button";
2106
+ option.className = "slash-completion-option";
2107
+ option.id = `slash-command-option-${index}`;
2108
+ option.dataset.commandIndex = String(index);
2109
+ option.setAttribute("role", "option");
2110
+ option.setAttribute("aria-selected", String(selected));
2111
+ const name = textElement("span", "slash-completion-name", `/${command.name}`);
2112
+ option.append(name);
2113
+ if (command.description) {
2114
+ option.append(textElement("span", "slash-completion-description", command.description));
2115
+ }
2116
+ option.addEventListener("pointerdown", (event) => event.preventDefault());
2117
+ option.addEventListener("click", () => {
2118
+ if (!slashCompletion) {
2119
+ return;
2120
+ }
2121
+ slashCompletion = { ...slashCompletion, selectedIndex: index };
2122
+ applySelectedSlashCompletion(false);
2123
+ });
2124
+ return option;
2125
+ });
2126
+ elements.slashCompletion.replaceChildren(...options);
2127
+ elements.slashCompletion.hidden = false;
2128
+ elements.prompt.setAttribute("aria-expanded", "true");
2129
+ elements.prompt.setAttribute("aria-activedescendant", `slash-command-option-${nextState.selectedIndex}`);
2130
+ }
2131
+ function setPromptValue(value) {
2132
+ dismissedSlashCompletionValue = void 0;
2133
+ elements.prompt.value = value;
2134
+ resizePrompt();
2135
+ renderSlashCompletion(true);
2136
+ }
2137
+ function updateControls() {
2138
+ const selected = currentSessionId !== void 0;
2139
+ const working = currentRuntime?.isWorking ?? false;
2140
+ elements.prompt.disabled = !selected;
2141
+ elements.send.disabled = !selected || sending;
2142
+ elements.abort.disabled = !selected || !working || sending;
2143
+ elements.sessionTitle.disabled = !selected || renaming;
2144
+ renderSlashCompletion();
2145
+ }
2146
+ function setContextValue(element, value, title = value) {
2147
+ element.textContent = value;
2148
+ element.title = value ? title : "";
2149
+ }
2150
+ function setWorkspaceRow(row, path, value = "", title = value) {
2151
+ row.hidden = !value;
2152
+ setContextValue(path, value, title);
2153
+ }
2154
+ function setWorkspace(cwd, context) {
2155
+ elements.sessionWorkspaceState.hidden = true;
2156
+ setContextValue(elements.sessionWorkspaceState, "");
2157
+ setWorkspaceRow(elements.sessionWorkspaceRepository, elements.sessionWorkspaceRepositoryPath);
2158
+ setWorkspaceRow(elements.sessionWorkspaceWorktree, elements.sessionWorkspaceWorktreePath);
2159
+ setWorkspaceRow(elements.sessionWorkspaceWorkingDirectory, elements.sessionWorkspaceWorkingDirectoryPath);
2160
+ if (context === void 0) {
2161
+ return;
2162
+ }
2163
+ if (context === null) {
2164
+ elements.sessionWorkspaceState.hidden = false;
2165
+ setContextValue(elements.sessionWorkspaceState, "Not a Git working tree");
2166
+ setWorkspaceRow(elements.sessionWorkspaceWorkingDirectory, elements.sessionWorkspaceWorkingDirectoryPath, cwd);
2167
+ return;
2168
+ }
2169
+ setWorkspaceRow(elements.sessionWorkspaceRepository, elements.sessionWorkspaceRepositoryPath, context.repositoryRoot);
2170
+ if (context.isLinkedWorktree) {
2171
+ const relativeWorktree = relativePathWithin(context.repositoryRoot, context.worktreeRoot);
2172
+ const worktreePath = relativeWorktree && relativeWorktree !== "." ? relativeWorktree : context.worktreeRoot;
2173
+ setWorkspaceRow(
2174
+ elements.sessionWorkspaceWorktree,
2175
+ elements.sessionWorkspaceWorktreePath,
2176
+ worktreePath,
2177
+ context.worktreeRoot
2178
+ );
2179
+ }
2180
+ setWorkspaceRow(elements.sessionWorkspaceWorkingDirectory, elements.sessionWorkspaceWorkingDirectoryPath, cwd);
2181
+ }
2182
+ function updateSessionUsage(usage, autoCompactionEnabled = false) {
2183
+ const formatted = formatSessionUsage(usage, autoCompactionEnabled);
2184
+ const tokenLines = formatted.tokenLines.length > 0 ? formatted.tokenLines.map((line) => textElement("span", "session-token-line", line)) : [textElement("span", "session-token-line is-empty", "No usage yet")];
2185
+ for (const line of tokenLines) {
2186
+ line.setAttribute("aria-hidden", "true");
2187
+ }
2188
+ elements.sessionTokens.replaceChildren(...tokenLines);
2189
+ elements.sessionTokens.title = formatted.tokenAccessibleText;
2190
+ elements.sessionTokens.setAttribute("aria-label", formatted.tokenAccessibleText);
2191
+ const contextVisual = document.createElement("div");
2192
+ contextVisual.className = "session-context-usage-visual";
2193
+ contextVisual.setAttribute("aria-hidden", "true");
2194
+ const contextSummary = document.createElement("div");
2195
+ contextSummary.className = "session-context-usage-summary";
2196
+ contextSummary.append(textElement("span", "session-context-percentage", formatted.context.percentageText));
2197
+ if (formatted.context.capacityText) {
2198
+ contextSummary.append(textElement("span", "session-context-capacity", formatted.context.capacityText));
2199
+ }
2200
+ contextVisual.append(contextSummary);
2201
+ if (formatted.context.meterPercent !== null) {
2202
+ const meter = document.createElement("span");
2203
+ meter.className = "session-context-meter";
2204
+ const fill = document.createElement("span");
2205
+ fill.className = "session-context-meter-fill";
2206
+ fill.style.width = `${formatted.context.meterPercent}%`;
2207
+ meter.append(fill);
2208
+ contextVisual.append(meter);
2209
+ }
2210
+ if (formatted.context.autoCompactionEnabled) {
2211
+ contextVisual.append(textElement("span", "session-context-auto", "Auto-compact enabled"));
2212
+ }
2213
+ elements.sessionContextUsage.dataset.state = formatted.context.state;
2214
+ elements.sessionContextUsage.replaceChildren(contextVisual);
2215
+ elements.sessionContextUsage.title = formatted.context.accessibleText;
2216
+ elements.sessionContextUsage.setAttribute("aria-label", formatted.context.accessibleText);
2217
+ }
2218
+ function updateSessionContext() {
2219
+ const runtimeModel = currentRuntime?.model;
2220
+ const persistedModel = currentSession?.model;
2221
+ const modelIdentifier = runtimeModel ? `${runtimeModel.provider}/${runtimeModel.id}` : persistedModel ? `${persistedModel.provider}/${persistedModel.modelId}` : "Unavailable";
2222
+ const modelName = runtimeModel?.name.trim() || modelIdentifier;
2223
+ const thinking = currentRuntime?.thinkingLevel ?? currentSession?.thinkingLevel ?? "off";
2224
+ const modelValue = modelIdentifier === "Unavailable" ? modelIdentifier : `${modelName} (${thinking})`;
2225
+ const modelTitle = modelIdentifier === "Unavailable" ? modelIdentifier : `${modelIdentifier} \xB7 Thinking level: ${thinking}`;
2226
+ setContextValue(elements.sessionModel, modelValue, modelTitle);
2227
+ elements.sessionModel.setAttribute(
2228
+ "aria-label",
2229
+ modelIdentifier === "Unavailable" ? "Model unavailable" : `Model: ${modelName}; identifier: ${modelIdentifier}; thinking level: ${thinking}`
2230
+ );
2231
+ updateSessionUsage(currentRuntime?.usage ?? null, currentRuntime?.autoCompactionEnabled);
2232
+ }
2233
+ function safeJson(value) {
2234
+ try {
2235
+ return JSON.stringify(value, null, 2) ?? String(value);
2236
+ } catch {
2237
+ return String(value);
2238
+ }
2239
+ }
2240
+ function createActivityCard(group, running = false) {
2241
+ const root = document.createElement("details");
2242
+ root.className = "assistant-activity";
2243
+ root.open = false;
2244
+ root.dataset.state = running ? "running" : group?.outcome ?? "complete";
2245
+ const summary = document.createElement("summary");
2246
+ const icon = document.createElement("span");
2247
+ icon.className = "assistant-activity-status";
2248
+ icon.setAttribute("aria-hidden", "true");
2249
+ const summaryCopy = document.createElement("span");
2250
+ summaryCopy.className = "assistant-activity-summary-copy";
2251
+ const title = textElement(
2252
+ "span",
2253
+ "assistant-activity-title",
2254
+ group?.preview ?? (running ? "Working\u2026" : "Assistant activity")
2255
+ );
2256
+ const action = textElement("span", "assistant-activity-action", "");
2257
+ action.hidden = true;
2258
+ summaryCopy.append(title, action);
2259
+ const statusText = textElement(
2260
+ "span",
2261
+ "sr-only",
2262
+ running ? "Assistant working." : group?.outcome === "aborted" ? "Assistant work stopped." : "Assistant work complete."
2263
+ );
2264
+ summary.append(icon, summaryCopy, statusText);
2265
+ const content = document.createElement("div");
2266
+ content.className = "assistant-activity-content";
2267
+ root.append(summary, content);
2268
+ const card = {
2269
+ root,
2270
+ content,
2271
+ title,
2272
+ action,
2273
+ statusText,
2274
+ manuallyToggled: false
2275
+ };
2276
+ summary.addEventListener("click", () => {
2277
+ card.manuallyToggled = true;
2278
+ });
2279
+ summary.addEventListener("keydown", (event) => {
2280
+ if (event.key === "Enter" || event.key === " ") {
2281
+ card.manuallyToggled = true;
2282
+ }
2283
+ });
2284
+ if (group) {
2285
+ for (const item of group.items) {
2286
+ appendActivityItem2(card, item);
2287
+ }
2288
+ updateActivitySummary(card, group.preview, group.lastAction);
2289
+ }
2290
+ if (!running) {
2291
+ card.action.hidden = true;
2292
+ }
2293
+ return card;
2294
+ }
2295
+ function updateActivitySummary(card, preview, action) {
2296
+ if (preview) {
2297
+ card.title.textContent = preview;
2298
+ }
2299
+ if (action) {
2300
+ card.action.textContent = action;
2301
+ card.action.hidden = false;
2302
+ }
2303
+ }
2304
+ function setActivityRunning(card, running) {
2305
+ card.root.dataset.state = running ? "running" : "complete";
2306
+ card.statusText.textContent = running ? "Assistant working." : "Assistant work complete.";
2307
+ if (running && card.action.textContent) {
2308
+ card.action.hidden = false;
2309
+ } else if (!running) {
2310
+ card.action.hidden = true;
2311
+ }
2312
+ }
2313
+ function setActivityAborted(card) {
2314
+ card.root.dataset.state = "aborted";
2315
+ card.statusText.textContent = "Assistant work stopped.";
2316
+ card.action.hidden = true;
2317
+ collapseActivity(card);
2318
+ }
2319
+ function collapseActivity(card) {
2320
+ if (!card.manuallyToggled) {
2321
+ card.root.open = false;
2322
+ }
2323
+ }
2324
+ function appendActivityItem2(card, item, append = true) {
2325
+ const details = document.createElement("details");
2326
+ details.className = `assistant-activity-item ${item.kind}`;
2327
+ const summary = document.createElement("summary");
2328
+ const body = document.createElement("div");
2329
+ body.className = "assistant-activity-item-content";
2330
+ if (item.kind === "thinking") {
2331
+ summary.textContent = "Thinking";
2332
+ body.append(textElement("pre", "", item.text));
2333
+ const preview = activityPreview(item.text);
2334
+ updateActivitySummary(card, preview || void 0);
2335
+ } else if (item.kind === "toolCall") {
2336
+ summary.textContent = toolActionLabel(item.name);
2337
+ body.append(textElement("pre", "", safeJson(item.arguments)));
2338
+ updateActivitySummary(card, void 0, toolActionLabel(item.name));
2339
+ } else {
2340
+ summary.textContent = `Tool result \xB7 ${item.message.toolName ?? "tool"}`;
2341
+ appendContent(body, item.message.content);
2342
+ updateActivitySummary(card, void 0, toolActionLabel(item.message.toolName, true));
2343
+ }
2344
+ details.append(summary, body);
2345
+ if (append) {
2346
+ card.content.append(details);
2347
+ }
2348
+ return details;
2349
+ }
2350
+ function markdownElement(source) {
2351
+ const element = document.createElement("div");
2352
+ element.className = "message-text markdown-content";
2353
+ element.innerHTML = renderMarkdown(source);
2354
+ return element;
2355
+ }
2356
+ function appendContent(container, content, markdown = false) {
2357
+ if (typeof content === "string") {
2358
+ container.append(markdown ? markdownElement(content) : textElement("p", "message-text", content));
2359
+ return;
2360
+ }
2361
+ if (!Array.isArray(content)) {
2362
+ if (content !== void 0) {
2363
+ container.append(textElement("pre", "", safeJson(content)));
2364
+ }
2365
+ return;
2366
+ }
2367
+ for (const part of content) {
2368
+ if (!part || typeof part !== "object") {
2369
+ if (part !== void 0 && part !== null) {
2370
+ container.append(textElement("pre", "", safeJson(part)));
2371
+ }
2372
+ continue;
2373
+ }
2374
+ const block = part;
2375
+ if (block.type === "text") {
2376
+ const text = typeof block.text === "string" ? block.text : "";
2377
+ container.append(markdown ? markdownElement(text) : textElement("p", "message-text", text));
2378
+ continue;
2379
+ }
2380
+ if (block.type === "thinking") {
2381
+ const details = document.createElement("details");
2382
+ const summary = document.createElement("summary");
2383
+ summary.textContent = "Thinking";
2384
+ details.append(summary, textElement("pre", "", typeof block.thinking === "string" ? block.thinking : ""));
2385
+ container.append(details);
2386
+ continue;
2387
+ }
2388
+ if (block.type === "toolCall") {
2389
+ const details = document.createElement("details");
2390
+ const summary = document.createElement("summary");
2391
+ summary.textContent = `Tool \xB7 ${String(block.name ?? "unknown")}`;
2392
+ details.append(summary, textElement("pre", "", safeJson(block.arguments)));
2393
+ container.append(details);
2394
+ continue;
2395
+ }
2396
+ if (block.type === "image") {
2397
+ container.append(textElement("p", "message-text", "[Image]"));
2398
+ continue;
2399
+ }
2400
+ container.append(textElement("pre", "", safeJson(block)));
2401
+ }
2402
+ }
2403
+ function createMessage(message, label) {
2404
+ const collapsible = message.role === "toolResult" || message.role === "live-tool";
2405
+ let root;
2406
+ let header;
2407
+ let content;
2408
+ if (collapsible) {
2409
+ root = document.createElement("details");
2410
+ root.className = "message";
2411
+ header = document.createElement("summary");
2412
+ content = document.createElement("div");
2413
+ content.className = "message-content";
2414
+ root.append(header, content);
2415
+ } else {
2416
+ const template = requiredElement("#message-template");
2417
+ const fragment = template.content.cloneNode(true);
2418
+ root = requiredElement("article", fragment);
2419
+ header = requiredElement("header", root);
2420
+ content = requiredElement(".message-content", root);
2421
+ }
2422
+ root.classList.add(message.role);
2423
+ if (message.isError) {
2424
+ root.classList.add("error");
2425
+ }
2426
+ header.textContent = label ?? (message.role === "toolResult" ? `Tool result \xB7 ${message.toolName ?? "tool"}` : message.role === "custom" ? "extension" : message.role);
2427
+ appendContent(content, message.content, message.role === "assistant");
2428
+ return root;
2429
+ }
2430
+ function renderEmpty(title, description) {
2431
+ const empty = document.createElement("div");
2432
+ empty.className = "empty-state";
2433
+ empty.append(textElement("strong", "", title), textElement("span", "", description));
2434
+ elements.transcript.replaceChildren(empty);
2435
+ }
2436
+ function setSubmittedTurnAnchor(active) {
2437
+ elements.transcript.classList.toggle("has-submitted-turn-anchor", active);
2438
+ if (!active) {
2439
+ elements.transcript.style.removeProperty("--submitted-turn-runway");
2440
+ }
2441
+ }
2442
+ function updateSubmittedTurnRunway() {
2443
+ submittedTurnRunwayFrame = void 0;
2444
+ const turn = submittedTurnAnchor;
2445
+ if (!turn || turn.sessionId !== currentSessionId || !turn.root.isConnected) {
2446
+ return;
2447
+ }
2448
+ const transcriptRect = elements.transcript.getBoundingClientRect();
2449
+ const rootRect = turn.root.getBoundingClientRect();
2450
+ const scrollPadding = Number.parseFloat(getComputedStyle(elements.transcript).scrollPaddingBlockStart) || 0;
2451
+ const rootContentTop = elements.transcript.scrollTop + rootRect.top - transcriptRect.top;
2452
+ const anchoredScrollTop = Math.max(0, rootContentTop - scrollPadding);
2453
+ const previousScrollTop = elements.transcript.scrollTop;
2454
+ elements.transcript.style.setProperty("--submitted-turn-runway", "0px");
2455
+ const naturalScrollHeight = elements.transcript.scrollHeight;
2456
+ const runway = Math.max(0, Math.ceil(anchoredScrollTop + elements.transcript.clientHeight - naturalScrollHeight));
2457
+ elements.transcript.style.setProperty("--submitted-turn-runway", `${runway}px`);
2458
+ const maximumScrollTop = elements.transcript.scrollHeight - elements.transcript.clientHeight;
2459
+ elements.transcript.scrollTop = Math.min(previousScrollTop, maximumScrollTop);
2460
+ }
2461
+ function scheduleSubmittedTurnRunwayUpdate() {
2462
+ if (submittedTurnRunwayFrame !== void 0) {
2463
+ return;
2464
+ }
2465
+ submittedTurnRunwayFrame = requestAnimationFrame(updateSubmittedTurnRunway);
2466
+ }
2467
+ function alignSubmittedTurn(root) {
2468
+ const turn = submittedTurnAnchor;
2469
+ if (!turn || turn.sessionId !== currentSessionId) {
2470
+ return;
2471
+ }
2472
+ turn.root = root;
2473
+ updateSubmittedTurnRunway();
2474
+ if (!turn.needsAlignment) {
2475
+ return;
2476
+ }
2477
+ root.scrollIntoView({ block: "start" });
2478
+ turn.needsAlignment = false;
2479
+ }
2480
+ function insertBeforePendingQueue(node) {
2481
+ const firstPending = elements.transcript.querySelector("[data-pending-steering]");
2482
+ elements.transcript.insertBefore(node, firstPending);
2483
+ }
2484
+ function renderPendingQueue() {
2485
+ for (const pending of elements.transcript.querySelectorAll("[data-pending-steering]")) {
2486
+ pending.remove();
2487
+ }
2488
+ const messages = currentRuntime?.queue.steering ?? [];
2489
+ if (messages.length === 0) {
2490
+ return;
2491
+ }
2492
+ elements.transcript.querySelector(".empty-state")?.remove();
2493
+ messages.forEach((message, index) => {
2494
+ const root = createMessage({ role: "user", content: message });
2495
+ root.classList.add("pending");
2496
+ root.dataset.pendingSteering = "true";
2497
+ root.dataset.state = "pending";
2498
+ const header = requiredElement("header", root);
2499
+ const label = textElement("span", "pending-message-label", "Pending");
2500
+ const remove = textElement("button", "pending-message-remove", "\xD7");
2501
+ const removeLabel = `Remove pending message ${index + 1}`;
2502
+ remove.type = "button";
2503
+ remove.disabled = sending;
2504
+ remove.title = removeLabel;
2505
+ remove.setAttribute("aria-label", removeLabel);
2506
+ remove.addEventListener("click", () => void removePendingSteering(index, message));
2507
+ header.replaceChildren(label, remove);
2508
+ elements.transcript.append(root);
2509
+ });
2510
+ }
2511
+ function anchorPendingSteeringMessage(index) {
2512
+ const pending = elements.transcript.querySelectorAll("[data-pending-steering]")[index];
2513
+ if (pending) {
2514
+ alignSubmittedTurn(pending);
2515
+ }
2516
+ }
2517
+ function renderConversation(session, runtime) {
2518
+ const preservedActivityOpen = liveActivity?.manuallyToggled ? liveActivity.root.open : void 0;
2519
+ const preservedActivityAborted = liveActivity?.root.dataset.state === "aborted";
2520
+ liveMessage = void 0;
2521
+ liveActivity = void 0;
2522
+ resetStreamBlocks();
2523
+ liveTools.clear();
2524
+ const fragment = document.createDocumentFragment();
2525
+ let latestTurnActivity;
2526
+ for (const entry of groupTranscriptActivity(session.transcriptEntries)) {
2527
+ if (entry.kind === "activity") {
2528
+ latestTurnActivity = createActivityCard(entry);
2529
+ fragment.append(latestTurnActivity.root);
2530
+ continue;
2531
+ }
2532
+ if (entry.kind === "message") {
2533
+ if (entry.message.role === "user") {
2534
+ latestTurnActivity = void 0;
2535
+ }
2536
+ if (entry.message.role !== "custom" || entry.message.display !== false) {
2537
+ fragment.append(createMessage(entry.message));
2538
+ }
2539
+ continue;
2540
+ }
2541
+ if (!entry.data || typeof entry.data !== "object") {
2542
+ continue;
2543
+ }
2544
+ const data = entry.data;
2545
+ if (typeof data.markdown !== "string") {
2546
+ continue;
2547
+ }
2548
+ const fileName = typeof data.path === "string" ? data.path.split("/").at(-1) : void 0;
2549
+ const label = fileName ? `extension snapshot \xB7 ${fileName}` : "extension snapshot";
2550
+ const snapshot = createMessage({ role: "extension", content: [] }, label);
2551
+ requiredElement(".message-content", snapshot).append(markdownElement(data.markdown));
2552
+ fragment.append(snapshot);
2553
+ }
2554
+ if (fragment.childNodes.length === 0 && !runtime?.isWorking && !runtime?.queue.steering.length) {
2555
+ renderEmpty("Start a conversation", "Send a message to begin this session.");
2556
+ } else {
2557
+ elements.transcript.replaceChildren(fragment);
2558
+ }
2559
+ if (latestTurnActivity && preservedActivityOpen !== void 0) {
2560
+ latestTurnActivity.manuallyToggled = true;
2561
+ latestTurnActivity.root.open = preservedActivityOpen;
2562
+ }
2563
+ if (runtime?.isWorking) {
2564
+ liveActivity = latestTurnActivity ?? ensureLiveActivity();
2565
+ if (preservedActivityOpen !== void 0) {
2566
+ liveActivity.manuallyToggled = true;
2567
+ liveActivity.root.open = preservedActivityOpen;
2568
+ }
2569
+ setActivityRunning(liveActivity, true);
2570
+ if (runtime.streamingMessage) {
2571
+ hydrateStreamingMessage(runtime.streamingMessage);
2572
+ }
2573
+ } else if (preservedActivityAborted) {
2574
+ liveActivity = latestTurnActivity ?? ensureLiveActivity();
2575
+ setActivityAborted(liveActivity);
2576
+ }
2577
+ renderPendingQueue();
2578
+ }
2579
+ function ensureLiveActivity() {
2580
+ if (liveActivity) {
2581
+ return liveActivity;
2582
+ }
2583
+ elements.transcript.querySelector(".empty-state")?.remove();
2584
+ liveActivity = createActivityCard(void 0, true);
2585
+ insertBeforePendingQueue(liveActivity.root);
2586
+ return liveActivity;
2587
+ }
2588
+ function ensureLiveMessage() {
2589
+ if (liveMessage) {
2590
+ return liveMessage;
2591
+ }
2592
+ const activity = ensureLiveActivity();
2593
+ collapseActivity(activity);
2594
+ const root = createMessage({ role: "assistant", content: [] }, "assistant \xB7 streaming");
2595
+ const content = requiredElement(".message-content", root);
2596
+ liveMessage = { root, content };
2597
+ insertBeforePendingQueue(root);
2598
+ return liveMessage;
2599
+ }
2600
+ function renderLiveMarkdown(block) {
2601
+ if (block.kind !== "text") {
2602
+ return;
2603
+ }
2604
+ block.target.innerHTML = renderMarkdown(block.source ?? "");
2605
+ }
2606
+ function flushLiveMarkdown() {
2607
+ markdownRenderFrame = void 0;
2608
+ const blocks = [...pendingMarkdownBlocks];
2609
+ pendingMarkdownBlocks.clear();
2610
+ for (const block of blocks) {
2611
+ renderLiveMarkdown(block);
2612
+ }
2613
+ }
2614
+ function scheduleLiveMarkdown(block) {
2615
+ pendingMarkdownBlocks.add(block);
2616
+ if (markdownRenderFrame !== void 0) {
2617
+ return;
2618
+ }
2619
+ markdownRenderFrame = requestAnimationFrame(flushLiveMarkdown);
2620
+ }
2621
+ function resetStreamBlocks() {
2622
+ if (markdownRenderFrame !== void 0) {
2623
+ cancelAnimationFrame(markdownRenderFrame);
2624
+ }
2625
+ markdownRenderFrame = void 0;
2626
+ pendingMarkdownBlocks.clear();
2627
+ streamBlocks = /* @__PURE__ */ new Map();
2628
+ }
2629
+ function ensureStreamBlock(index, kind, initial) {
2630
+ const existing = streamBlocks.get(index);
2631
+ if (existing) {
2632
+ return existing;
2633
+ }
2634
+ let block;
2635
+ if (kind === "thinking") {
2636
+ const card = ensureLiveActivity();
2637
+ const details = appendActivityItem2(card, { kind: "thinking", text: "" });
2638
+ block = {
2639
+ kind,
2640
+ target: requiredElement("pre", details),
2641
+ summary: requiredElement("summary", details)
2642
+ };
2643
+ } else if (kind.toLowerCase().startsWith("toolcall")) {
2644
+ const name = String(initial?.toolName ?? initial?.name ?? "tool");
2645
+ const card = ensureLiveActivity();
2646
+ const details = appendActivityItem2(card, { kind: "toolCall", name, arguments: {} });
2647
+ block = {
2648
+ kind: "toolcall",
2649
+ target: requiredElement("pre", details),
2650
+ summary: requiredElement("summary", details)
2651
+ };
2652
+ } else {
2653
+ const live = ensureLiveMessage();
2654
+ const markdown = markdownElement("");
2655
+ live.content.append(markdown);
2656
+ block = { kind: "text", target: markdown, source: "" };
2657
+ }
2658
+ streamBlocks.set(index, block);
2659
+ return block;
2660
+ }
2661
+ function hydrateStreamingMessage(partial) {
2662
+ resetStreamBlocks();
2663
+ if (typeof partial.content === "string") {
2664
+ const block = ensureStreamBlock(0, "text");
2665
+ block.source = partial.content;
2666
+ renderLiveMarkdown(block);
2667
+ return;
2668
+ }
2669
+ if (!Array.isArray(partial.content)) {
2670
+ return;
2671
+ }
2672
+ partial.content.forEach((part, index) => {
2673
+ if (!part || typeof part !== "object") {
2674
+ return;
2675
+ }
2676
+ const value = part;
2677
+ const kind = typeof value.type === "string" ? value.type : "text";
2678
+ const block = ensureStreamBlock(index, kind, value);
2679
+ if (kind === "text" && typeof value.text === "string") {
2680
+ block.source = value.text;
2681
+ renderLiveMarkdown(block);
2682
+ }
2683
+ if (kind === "thinking" && typeof value.thinking === "string") {
2684
+ block.target.textContent = value.thinking;
2685
+ updateActivitySummary(ensureLiveActivity(), activityPreview(value.thinking) || void 0);
2686
+ }
2687
+ if (kind === "toolCall" && value.arguments !== void 0) {
2688
+ block.target.textContent = safeJson(value.arguments);
2689
+ }
2690
+ });
2691
+ }
2692
+ function handleMessageUpdate(event) {
2693
+ const update = event.assistantMessageEvent;
2694
+ if (!update || typeof update !== "object") {
2695
+ return;
2696
+ }
2697
+ const delta = update;
2698
+ const type = typeof delta.type === "string" ? delta.type : "";
2699
+ const index = typeof delta.contentIndex === "number" ? delta.contentIndex : 0;
2700
+ if (type === "text_start") {
2701
+ ensureStreamBlock(index, "text");
2702
+ }
2703
+ if (type === "thinking_start") {
2704
+ ensureStreamBlock(index, "thinking");
2705
+ }
2706
+ if (type === "toolcall_start") {
2707
+ ensureStreamBlock(index, "toolcall", delta);
2708
+ }
2709
+ if (type === "text_delta" || type === "thinking_delta" || type === "toolcall_delta") {
2710
+ const kind = type === "thinking_delta" ? "thinking" : type === "toolcall_delta" ? "toolcall" : "text";
2711
+ const block = ensureStreamBlock(index, kind, delta);
2712
+ if (typeof delta.delta === "string") {
2713
+ if (kind === "text") {
2714
+ block.source = (block.source ?? "") + delta.delta;
2715
+ scheduleLiveMarkdown(block);
2716
+ } else {
2717
+ block.target.append(document.createTextNode(delta.delta));
2718
+ }
2719
+ }
2720
+ if (kind === "thinking") {
2721
+ updateActivitySummary(ensureLiveActivity(), activityPreview(block.target.textContent ?? "") || void 0);
2722
+ }
2723
+ }
2724
+ if (type === "toolcall_end") {
2725
+ const block = ensureStreamBlock(index, "toolcall", delta);
2726
+ const toolCall = delta.toolCall;
2727
+ const name = toolCall?.name ?? delta.toolName;
2728
+ if (block.summary) {
2729
+ block.summary.textContent = toolActionLabel(name);
2730
+ }
2731
+ if (toolCall?.arguments !== void 0) {
2732
+ block.target.textContent = safeJson(toolCall.arguments);
2733
+ }
2734
+ updateActivitySummary(ensureLiveActivity(), void 0, toolActionLabel(name));
2735
+ }
2736
+ }
2737
+ function resultText(value) {
2738
+ if (!value || typeof value !== "object") {
2739
+ return "";
2740
+ }
2741
+ const content = value.content;
2742
+ if (!Array.isArray(content)) {
2743
+ return "";
2744
+ }
2745
+ return content.filter(
2746
+ (part) => Boolean(
2747
+ part && typeof part === "object" && part.type === "text" && typeof part.text === "string"
2748
+ )
2749
+ ).map((part) => part.text).join("\n");
2750
+ }
2751
+ function updateTool(event, finished) {
2752
+ const id = typeof event.toolCallId === "string" ? event.toolCallId : void 0;
2753
+ if (!id) {
2754
+ return;
2755
+ }
2756
+ const card = ensureLiveActivity();
2757
+ const name = String(event.toolName ?? "tool");
2758
+ let root = liveTools.get(id);
2759
+ if (!root) {
2760
+ root = document.createElement("details");
2761
+ root.className = "assistant-activity-item toolResult live-tool";
2762
+ const summary = textElement("summary", "", `Tool result \xB7 ${name}`);
2763
+ const content2 = document.createElement("div");
2764
+ content2.className = "assistant-activity-item-content";
2765
+ root.append(summary, content2);
2766
+ card.content.append(root);
2767
+ liveTools.set(id, root);
2768
+ }
2769
+ const content = requiredElement(".assistant-activity-item-content", root);
2770
+ const result = finished ? event.result : event.partialResult;
2771
+ content.replaceChildren(textElement("pre", "", resultText(result)));
2772
+ if (finished) {
2773
+ requiredElement("summary", root).textContent = `Tool result \xB7 ${name} \xB7 done`;
2774
+ }
2775
+ updateActivitySummary(card, void 0, toolActionLabel(name, finished));
2776
+ }
2777
+ function messageText(message) {
2778
+ if (typeof message.content === "string") {
2779
+ return message.content;
2780
+ }
2781
+ if (!Array.isArray(message.content)) {
2782
+ return void 0;
2783
+ }
2784
+ const text = message.content.filter(
2785
+ (part) => Boolean(
2786
+ part && typeof part === "object" && part.type === "text" && typeof part.text === "string"
2787
+ )
2788
+ ).map((part) => part.text).join("\n");
2789
+ return text || void 0;
2790
+ }
2791
+ function appendUserMessage(message) {
2792
+ const text = messageText(message);
2793
+ const candidate = optimisticSubmission;
2794
+ const optimistic = candidate && candidate.sessionId === currentSessionId && candidate.root.isConnected && candidate.message === text ? candidate : void 0;
2795
+ const dequeuedIndex = text === void 0 ? -1 : dequeuedSteering.indexOf(text);
2796
+ if (!optimistic && dequeuedIndex < 0) {
2797
+ return;
2798
+ }
2799
+ if (dequeuedIndex >= 0) {
2800
+ dequeuedSteering.splice(dequeuedIndex, 1);
2801
+ }
2802
+ const final = createMessage(message);
2803
+ if (optimistic) {
2804
+ optimistic.root.replaceWith(final);
2805
+ optimisticSubmission = void 0;
2806
+ alignSubmittedTurn(final);
2807
+ } else {
2808
+ insertBeforePendingQueue(final);
2809
+ const turn = submittedTurnAnchor;
2810
+ if (turn && turn.sessionId === currentSessionId && turn.message === text) {
2811
+ alignSubmittedTurn(final);
2812
+ }
2813
+ }
2814
+ if (!optimistic) {
2815
+ if (liveActivity) {
2816
+ setActivityRunning(liveActivity, false);
2817
+ collapseActivity(liveActivity);
2818
+ }
2819
+ liveMessage = void 0;
2820
+ liveActivity = void 0;
2821
+ resetStreamBlocks();
2822
+ liveTools.clear();
2823
+ }
2824
+ }
2825
+ function appendMessage(message) {
2826
+ if (message.role === "custom" && message.display === false) {
2827
+ return;
2828
+ }
2829
+ elements.transcript.querySelector(".empty-state")?.remove();
2830
+ if (message.role === "user") {
2831
+ appendUserMessage(message);
2832
+ } else if (message.role === "assistant") {
2833
+ const partitioned = partitionAssistantContent(message.content);
2834
+ const sawStreamedActivity = [...streamBlocks.values()].some((block) => block.kind !== "text");
2835
+ if (!sawStreamedActivity) {
2836
+ const card = partitioned.activity.length > 0 ? ensureLiveActivity() : void 0;
2837
+ if (card) {
2838
+ for (const item of partitioned.activity) {
2839
+ appendActivityItem2(card, item);
2840
+ }
2841
+ }
2842
+ }
2843
+ if (partitioned.hasResponse) {
2844
+ const final = createMessage({ ...message, content: partitioned.responseContent });
2845
+ collapseActivity(ensureLiveActivity());
2846
+ if (liveMessage) {
2847
+ liveMessage.root.replaceWith(final);
2848
+ } else {
2849
+ insertBeforePendingQueue(final);
2850
+ }
2851
+ liveMessage = void 0;
2852
+ }
2853
+ if (message.stopReason === "aborted") {
2854
+ setActivityAborted(ensureLiveActivity());
2855
+ }
2856
+ resetStreamBlocks();
2857
+ } else if (message.role === "toolResult") {
2858
+ const card = ensureLiveActivity();
2859
+ const placeholder = message.toolCallId ? liveTools.get(message.toolCallId) : void 0;
2860
+ const final = appendActivityItem2(card, { kind: "toolResult", message }, !placeholder);
2861
+ if (placeholder) {
2862
+ placeholder.replaceWith(final);
2863
+ }
2864
+ if (message.toolCallId) {
2865
+ liveTools.delete(message.toolCallId);
2866
+ }
2867
+ } else {
2868
+ insertBeforePendingQueue(createMessage(message));
2869
+ }
2870
+ }
2871
+ function appendError(message) {
2872
+ const root = createMessage({ role: "error", content: message, isError: true }, "error");
2873
+ elements.transcript.querySelector(".empty-state")?.remove();
2874
+ insertBeforePendingQueue(root);
2875
+ }
2876
+ function cloneExtensionUIState(state) {
2877
+ return state ? {
2878
+ pending: state.pending.map((request) => ({ ...request })),
2879
+ statuses: state.statuses.map((status) => ({ ...status })),
2880
+ widgets: state.widgets.map((widget) => ({ ...widget, lines: [...widget.lines] }))
2881
+ } : { pending: [], statuses: [], widgets: [] };
2882
+ }
2883
+ function renderExtensionState() {
2884
+ const statuses = document.createDocumentFragment();
2885
+ for (const status of extensionUI.statuses) {
2886
+ statuses.append(textElement("span", "extension-status", status.text));
2887
+ }
2888
+ const above = document.createDocumentFragment();
2889
+ const below = document.createDocumentFragment();
2890
+ for (const widget of extensionUI.widgets) {
2891
+ const section = document.createElement("section");
2892
+ section.className = "extension-widget";
2893
+ section.append(textElement("pre", "extension-widget-content", widget.lines.join("\n")));
2894
+ (widget.placement === "belowEditor" ? below : above).append(section);
2895
+ }
2896
+ const hasStatuses = statuses.childNodes.length > 0;
2897
+ const hasAbove = above.childNodes.length > 0;
2898
+ const hasBelow = below.childNodes.length > 0;
2899
+ elements.extensionStatuses.replaceChildren(statuses);
2900
+ elements.extensionWidgetsAbove.replaceChildren(above);
2901
+ elements.extensionWidgetsBelow.replaceChildren(below);
2902
+ elements.extensionStatusItem.hidden = !hasStatuses;
2903
+ elements.extensionStatuses.hidden = !hasStatuses;
2904
+ elements.extensionWidgetsAbove.hidden = !hasAbove;
2905
+ elements.extensionWidgetsBelow.hidden = !hasBelow;
2906
+ }
2907
+ async function respondToExtensionUI(request, response, reconcileAfterResponse = true) {
2908
+ if (!currentSessionId) {
2909
+ return;
2910
+ }
2911
+ const sessionId = currentSessionId;
2912
+ applyExtensionUIState({
2913
+ ...extensionUI,
2914
+ pending: extensionUI.pending.filter((candidate) => candidate.id !== request.id)
2915
+ });
2916
+ try {
2917
+ await api(`/api/sessions/${encodeURIComponent(sessionId)}/extension-ui`, {
2918
+ method: "POST",
2919
+ headers: { "content-type": "application/json" },
2920
+ body: JSON.stringify({ type: "extension_ui_response", id: request.id, ...response })
2921
+ });
2922
+ if (currentSessionId === sessionId && reconcileAfterResponse) {
2923
+ await reconcileSession();
2924
+ }
2925
+ } catch (error) {
2926
+ appendError(`Could not answer extension request: ${readableError(error)}`);
2927
+ if (currentSessionId === sessionId && reconcileAfterResponse) {
2928
+ void reconcileSession();
2929
+ }
2930
+ }
2931
+ }
2932
+ function renderExtensionPrompt() {
2933
+ const request = extensionUI.pending[0];
2934
+ if (!request) {
2935
+ const closedRequest = renderedExtensionRequestId !== void 0;
2936
+ renderedExtensionRequestId = void 0;
2937
+ elements.extensionPrompt.hidden = true;
2938
+ elements.extensionPrompt.replaceChildren();
2939
+ if (closedRequest && currentSessionId) {
2940
+ queueMicrotask(() => elements.prompt.focus());
2941
+ }
2942
+ return;
2943
+ }
2944
+ if (request.id === renderedExtensionRequestId && elements.extensionPrompt.childElementCount > 0) {
2945
+ return;
2946
+ }
2947
+ renderedExtensionRequestId = request.id;
2948
+ const panel = document.createElement("section");
2949
+ panel.className = "extension-prompt-panel";
2950
+ panel.setAttribute("role", "dialog");
2951
+ panel.setAttribute("aria-labelledby", "extension-prompt-title");
2952
+ panel.addEventListener("keydown", (event) => {
2953
+ if (event.key !== "Escape") {
2954
+ return;
2955
+ }
2956
+ event.preventDefault();
2957
+ void respondToExtensionUI(request, { cancelled: true });
2958
+ });
2959
+ const header = document.createElement("header");
2960
+ const title = document.createElement("h2");
2961
+ title.id = "extension-prompt-title";
2962
+ const titleToggle = textElement("button", "extension-prompt-title-toggle", request.title);
2963
+ titleToggle.type = "button";
2964
+ title.append(titleToggle);
2965
+ const body = document.createElement("div");
2966
+ body.id = "extension-prompt-body";
2967
+ body.className = "extension-prompt-body";
2968
+ const actions = document.createElement("footer");
2969
+ actions.id = "extension-prompt-actions";
2970
+ actions.className = "extension-prompt-actions";
2971
+ titleToggle.setAttribute("aria-controls", `${body.id} ${actions.id}`);
2972
+ const setCollapsed = (collapsed) => {
2973
+ const label = `${collapsed ? "Expand" : "Collapse"} extension request`;
2974
+ panel.classList.toggle("is-collapsed", collapsed);
2975
+ titleToggle.title = label;
2976
+ titleToggle.setAttribute("aria-expanded", String(!collapsed));
2977
+ };
2978
+ const toggleCollapsed = () => {
2979
+ setCollapsed(!panel.classList.contains("is-collapsed"));
2980
+ };
2981
+ setCollapsed(false);
2982
+ titleToggle.addEventListener("click", toggleCollapsed);
2983
+ titleToggle.addEventListener("keydown", (event) => {
2984
+ if (event.key !== "Enter" && event.key !== " ") {
2985
+ return;
2986
+ }
2987
+ event.preventDefault();
2988
+ toggleCollapsed();
2989
+ });
2990
+ const cancel = textElement("button", "extension-prompt-cancel secondary", "Cancel");
2991
+ cancel.type = "button";
2992
+ cancel.addEventListener("click", () => void respondToExtensionUI(request, { cancelled: true }));
2993
+ const headerActions = document.createElement("div");
2994
+ headerActions.className = "extension-prompt-header-actions";
2995
+ headerActions.append(cancel);
2996
+ header.append(title, headerActions);
2997
+ header.addEventListener("click", (event) => {
2998
+ if (event.target instanceof Element && event.target.closest("button")) {
2999
+ return;
3000
+ }
3001
+ toggleCollapsed();
3002
+ });
3003
+ let initialFocus = cancel;
3004
+ if (request.method === "select") {
3005
+ const choices = document.createElement("div");
3006
+ choices.className = "extension-prompt-choices";
3007
+ for (const option of request.options) {
3008
+ const button = textElement("button", "secondary", option);
3009
+ button.type = "button";
3010
+ button.addEventListener("click", () => void respondToExtensionUI(request, { value: option }));
3011
+ choices.append(button);
3012
+ if (choices.childElementCount === 1) {
3013
+ initialFocus = button;
3014
+ }
3015
+ }
3016
+ body.append(choices);
3017
+ } else if (request.method === "confirm") {
3018
+ body.append(textElement("p", "message-text", request.message));
3019
+ const confirm = textElement("button", "", "Confirm");
3020
+ confirm.type = "button";
3021
+ confirm.addEventListener("click", () => void respondToExtensionUI(request, { confirmed: true }));
3022
+ actions.append(confirm);
3023
+ initialFocus = confirm;
3024
+ } else {
3025
+ const field = request.method === "editor" ? document.createElement("textarea") : document.createElement("input");
3026
+ field.className = "extension-prompt-field";
3027
+ if (field instanceof HTMLTextAreaElement) {
3028
+ field.rows = 8;
3029
+ field.value = "prefill" in request ? request.prefill ?? "" : "";
3030
+ } else {
3031
+ field.type = "text";
3032
+ field.placeholder = "placeholder" in request ? request.placeholder ?? "" : "";
3033
+ }
3034
+ const submit = textElement("button", "", "Submit");
3035
+ submit.type = "button";
3036
+ submit.addEventListener("click", () => void respondToExtensionUI(request, { value: field.value }));
3037
+ field.addEventListener("keydown", (event) => {
3038
+ const keyboardEvent = event;
3039
+ if (keyboardEvent.key === "Enter" && (request.method === "input" || keyboardEvent.ctrlKey || keyboardEvent.metaKey)) {
3040
+ keyboardEvent.preventDefault();
3041
+ void respondToExtensionUI(request, { value: field.value });
3042
+ }
3043
+ });
3044
+ body.append(field);
3045
+ actions.append(submit);
3046
+ initialFocus = field;
3047
+ }
3048
+ panel.append(header, body, actions);
3049
+ elements.extensionPrompt.replaceChildren(panel);
3050
+ elements.extensionPrompt.hidden = false;
3051
+ queueMicrotask(() => initialFocus.focus());
3052
+ }
3053
+ function applyExtensionUIState(state) {
3054
+ extensionUI = cloneExtensionUIState(state);
3055
+ if (currentRuntime) {
3056
+ currentRuntime = { ...currentRuntime, extensionUI: cloneExtensionUIState(extensionUI) };
3057
+ }
3058
+ renderExtensionState();
3059
+ renderExtensionPrompt();
3060
+ updateControls();
3061
+ }
3062
+ function handleExtensionUIRequest(request) {
3063
+ if (request.method === "select" || request.method === "confirm" || request.method === "input" || request.method === "editor") {
3064
+ applyExtensionUIState({
3065
+ ...extensionUI,
3066
+ pending: [...extensionUI.pending.filter((candidate) => candidate.id !== request.id), request]
3067
+ });
3068
+ void reconcileSession();
3069
+ return;
3070
+ }
3071
+ if (request.method === "notify") {
3072
+ const notification = createMessage(
3073
+ { role: "extension", content: request.message, isError: request.notifyType === "error" },
3074
+ `extension \xB7 ${request.notifyType ?? "info"}`
3075
+ );
3076
+ elements.transcript.querySelector(".empty-state")?.remove();
3077
+ insertBeforePendingQueue(notification);
3078
+ return;
3079
+ }
3080
+ if (request.method === "setStatus") {
3081
+ const statuses = extensionUI.statuses.filter((status) => status.key !== request.statusKey);
3082
+ if (request.statusText !== void 0) {
3083
+ statuses.push({ key: request.statusKey, text: request.statusText });
3084
+ }
3085
+ applyExtensionUIState({ ...extensionUI, statuses });
3086
+ return;
3087
+ }
3088
+ if (request.method === "setWidget") {
3089
+ const widgets = extensionUI.widgets.filter((widget) => widget.key !== request.widgetKey);
3090
+ if (request.widgetLines !== void 0) {
3091
+ widgets.push({
3092
+ key: request.widgetKey,
3093
+ lines: [...request.widgetLines],
3094
+ placement: request.widgetPlacement ?? "aboveEditor"
3095
+ });
3096
+ }
3097
+ applyExtensionUIState({ ...extensionUI, widgets });
3098
+ return;
3099
+ }
3100
+ if (request.method === "setTitle") {
3101
+ document.title = request.title;
3102
+ return;
3103
+ }
3104
+ setPromptValue(request.text);
3105
+ }
3106
+ function applyRuntimeState(runtime) {
3107
+ const previousQueue = copyMessageQueue(currentRuntime?.queue);
3108
+ const nextRuntime = runtime ? { ...runtime, queue: copyMessageQueue(runtime.queue) } : null;
3109
+ if (!nextRuntime) {
3110
+ resetStreamBlocks();
3111
+ }
3112
+ const submittedQueueIndex = optimisticSubmission && nextRuntime && steeringQueueGrew(previousQueue, nextRuntime.queue) ? previousQueue.steering.length : void 0;
3113
+ if (submittedQueueIndex !== void 0) {
3114
+ optimisticSubmission?.root.remove();
3115
+ optimisticSubmission = void 0;
3116
+ }
3117
+ currentRuntime = nextRuntime;
3118
+ if (nextRuntime && currentSession) {
3119
+ if (nextRuntime.sessionName) {
3120
+ currentSession.name = nextRuntime.sessionName;
3121
+ } else {
3122
+ delete currentSession.name;
3123
+ }
3124
+ }
3125
+ applyExtensionUIState(nextRuntime?.extensionUI);
3126
+ renderPendingQueue();
3127
+ if (submittedQueueIndex !== void 0) {
3128
+ anchorPendingSteeringMessage(submittedQueueIndex);
3129
+ }
3130
+ updateControls();
3131
+ updateSessionContext();
3132
+ updateSessionHeading();
3133
+ }
3134
+ function patchRuntimeState(patch) {
3135
+ const existing = currentRuntime ?? emptyRuntime();
3136
+ currentRuntime = {
3137
+ ...existing,
3138
+ ...patch,
3139
+ queue: copyMessageQueue(patch.queue ?? existing.queue),
3140
+ extensionUI: cloneExtensionUIState(extensionUI)
3141
+ };
3142
+ renderPendingQueue();
3143
+ updateControls();
3144
+ updateSessionContext();
3145
+ }
3146
+ async function reconcileSession() {
3147
+ if (!currentSessionId) {
3148
+ return;
3149
+ }
3150
+ const selectedId = currentSessionId;
3151
+ const sequence = ++reconcileSequence;
3152
+ try {
3153
+ const response = await api(`/api/sessions/${encodeURIComponent(selectedId)}`);
3154
+ if (currentSessionId !== selectedId || sequence !== reconcileSequence) {
3155
+ return;
3156
+ }
3157
+ currentSession = response.session;
3158
+ applyRuntimeState(response.runtime);
3159
+ updateSessionHeading();
3160
+ setWorkspace(response.session.cwd, response.session.gitContext);
3161
+ optimisticSubmission = void 0;
3162
+ dequeuedSteering = [];
3163
+ renderConversation(response.session, currentRuntime);
3164
+ const latestUserEntry = [...response.session.transcriptEntries].reverse().find(
3165
+ (entry) => entry.kind === "message" && entry.message.role === "user"
3166
+ );
3167
+ if (submittedTurnAnchor?.sessionId === selectedId && latestUserEntry && messageText(latestUserEntry.message) === submittedTurnAnchor.message) {
3168
+ const renderedUsers = elements.transcript.querySelectorAll(".message.user:not(.pending)");
3169
+ const renderedUser = renderedUsers[renderedUsers.length - 1];
3170
+ if (renderedUser) {
3171
+ alignSubmittedTurn(renderedUser);
3172
+ }
3173
+ }
3174
+ } catch (error) {
3175
+ if (currentSessionId === selectedId && sequence === reconcileSequence) {
3176
+ appendError(readableError(error));
3177
+ }
3178
+ }
3179
+ }
3180
+ function handleAgentEvent(event) {
3181
+ const type = typeof event.type === "string" ? event.type : "";
3182
+ if (type === "agent_start") {
3183
+ patchRuntimeState({ isStreaming: true, isWorking: true });
3184
+ ensureLiveActivity();
3185
+ } else if (type === "message_start") {
3186
+ const message = event.message;
3187
+ if (message?.role === "assistant") {
3188
+ resetStreamBlocks();
3189
+ }
3190
+ } else if (type === "message_update") {
3191
+ handleMessageUpdate(event);
3192
+ } else if (type === "message_end") {
3193
+ const message = event.message;
3194
+ if (message) {
3195
+ appendMessage(message);
3196
+ }
3197
+ } else if (type === "entry_appended") {
3198
+ const entry = event.entry;
3199
+ if (entry?.type === "custom" || entry?.type === "custom_message") {
3200
+ void reconcileSession();
3201
+ }
3202
+ } else if (type === "tool_execution_start") {
3203
+ updateTool(event, false);
3204
+ patchRuntimeState({ isWorking: true });
3205
+ } else if (type === "tool_execution_update") {
3206
+ updateTool(event, false);
3207
+ } else if (type === "tool_execution_end") {
3208
+ updateTool(event, true);
3209
+ } else if (type === "queue_update") {
3210
+ const previousQueue = copyMessageQueue(currentRuntime?.queue);
3211
+ const update = reconcileMessageQueue(previousQueue, messageQueueFromEvent(event), discardingQueue);
3212
+ const pendingMessageCount = update.queue.steering.length + update.queue.followUp.length;
3213
+ const submittedQueueIndex = optimisticSubmission && steeringQueueGrew(previousQueue, update.queue) ? previousQueue.steering.length : void 0;
3214
+ if (discardingQueue) {
3215
+ dequeuedSteering = [];
3216
+ }
3217
+ dequeuedSteering.push(...update.dequeuedSteering);
3218
+ if (submittedQueueIndex !== void 0) {
3219
+ optimisticSubmission?.root.remove();
3220
+ optimisticSubmission = void 0;
3221
+ }
3222
+ patchRuntimeState({
3223
+ queue: update.queue,
3224
+ pendingMessageCount,
3225
+ ...pendingMessageCount > 0 ? { isWorking: true } : {}
3226
+ });
3227
+ if (submittedQueueIndex !== void 0) {
3228
+ anchorPendingSteeringMessage(submittedQueueIndex);
3229
+ }
3230
+ } else if (type === "compaction_start" || type === "auto_retry_start") {
3231
+ patchRuntimeState({ isCompacting: type === "compaction_start", isWorking: true });
3232
+ ensureLiveActivity();
3233
+ } else if (type === "session_info_changed") {
3234
+ const name = typeof event.name === "string" && event.name.trim() ? event.name.trim() : void 0;
3235
+ applyCurrentSessionName(name);
3236
+ } else if (type === "agent_settled") {
3237
+ dequeuedSteering = [];
3238
+ patchRuntimeState({
3239
+ isStreaming: false,
3240
+ isCompacting: false,
3241
+ isWorking: false,
3242
+ pendingMessageCount: 0,
3243
+ queue: { steering: [], followUp: [] }
3244
+ });
3245
+ if (liveActivity) {
3246
+ if (liveActivity.root.dataset.state !== "aborted") {
3247
+ setActivityRunning(liveActivity, false);
3248
+ }
3249
+ collapseActivity(liveActivity);
3250
+ }
3251
+ void reconcileSession();
3252
+ }
3253
+ }
3254
+ function emptyRuntime() {
3255
+ return {
3256
+ id: currentSessionId ?? "",
3257
+ cwd: currentSession?.cwd ?? "",
3258
+ isStreaming: false,
3259
+ isCompacting: false,
3260
+ isWorking: false,
3261
+ pendingMessageCount: 0,
3262
+ queue: { steering: [], followUp: [] },
3263
+ model: currentSession?.model ? {
3264
+ provider: currentSession.model.provider,
3265
+ id: currentSession.model.modelId,
3266
+ name: currentSession.model.modelId
3267
+ } : null,
3268
+ thinkingLevel: currentSession?.thinkingLevel ?? "off",
3269
+ autoCompactionEnabled: false,
3270
+ usage: {
3271
+ tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
3272
+ context: null
3273
+ },
3274
+ commands: [],
3275
+ extensionUI
3276
+ };
3277
+ }
3278
+ function handleRuntimeEnvelope(envelope) {
3279
+ if (envelope.type === "agent_event") {
3280
+ handleAgentEvent(envelope.event);
3281
+ }
3282
+ if (envelope.type === "extension_ui_request") {
3283
+ handleExtensionUIRequest(envelope);
3284
+ }
3285
+ if (envelope.type === "extension_ui_closed") {
3286
+ applyExtensionUIState({
3287
+ ...extensionUI,
3288
+ pending: extensionUI.pending.filter((request) => request.id !== envelope.id)
3289
+ });
3290
+ }
3291
+ if (envelope.type === "extension_ui_reset") {
3292
+ applyExtensionUIState(void 0);
3293
+ }
3294
+ if (envelope.type === "session_replaced" && envelope.sessionId !== currentSessionId) {
3295
+ void selectSession(envelope.sessionId);
3296
+ }
3297
+ if (envelope.type === "runtime_error") {
3298
+ appendError(envelope.message);
3299
+ void reconcileSession();
3300
+ }
3301
+ if (envelope.type === "runtime_disposed") {
3302
+ dequeuedSteering = [];
3303
+ resetStreamBlocks();
3304
+ patchRuntimeState({ pendingMessageCount: 0, queue: { steering: [], followUp: [] } });
3305
+ eventStream.reconnectNow();
3306
+ }
3307
+ }
3308
+ function renderConnectionState(state) {
3309
+ if (state === "connected") {
3310
+ setConnection("Connected", "online");
3311
+ } else if (state === "connecting") {
3312
+ setConnection("Connecting", "offline");
3313
+ } else {
3314
+ setConnection("Reconnecting", "error");
3315
+ }
3316
+ }
3317
+ var eventStream = new SessionEventStream({
3318
+ onStateChange: renderConnectionState,
3319
+ onReady: (event, recovered) => {
3320
+ if (!currentSessionId) {
3321
+ return;
3322
+ }
3323
+ try {
3324
+ const ready = JSON.parse(event.data);
3325
+ applyRuntimeState(ready.state);
3326
+ if (ready.state.isWorking) {
3327
+ setActivityRunning(ensureLiveActivity(), true);
3328
+ } else if (liveActivity) {
3329
+ if (liveActivity.root.dataset.state !== "aborted") {
3330
+ setActivityRunning(liveActivity, false);
3331
+ }
3332
+ collapseActivity(liveActivity);
3333
+ }
3334
+ if (ready.state.streamingMessage && !liveMessage && streamBlocks.size === 0) {
3335
+ hydrateStreamingMessage(ready.state.streamingMessage);
3336
+ }
3337
+ if (ready.gap || recovered) {
3338
+ void reconcileSession();
3339
+ }
3340
+ } catch (error) {
3341
+ appendError(`Could not read agent state: ${readableError(error)}`);
3342
+ }
3343
+ },
3344
+ onRuntime: (event) => {
3345
+ if (!currentSessionId) {
3346
+ return;
3347
+ }
3348
+ try {
3349
+ handleRuntimeEnvelope(JSON.parse(event.data));
3350
+ } catch (error) {
3351
+ appendError(`Could not read agent event: ${readableError(error)}`);
3352
+ }
3353
+ }
3354
+ });
3355
+ function connectEvents(id) {
3356
+ eventStream.start(id);
3357
+ }
3358
+ async function selectSession(id, updateHistory = true) {
3359
+ if (id === currentSessionId && currentSession) {
3360
+ return;
3361
+ }
3362
+ eventStream.stop();
3363
+ setSubmittedTurnAnchor(false);
3364
+ currentSessionId = id;
3365
+ currentSession = void 0;
3366
+ elements.createSession.href = `${sessionPath(id)}/new`;
3367
+ currentRuntime = null;
3368
+ applyExtensionUIState(void 0);
3369
+ optimisticSubmission = void 0;
3370
+ submittedTurnAnchor = void 0;
3371
+ dequeuedSteering = [];
3372
+ discardingQueue = false;
3373
+ liveMessage = void 0;
3374
+ liveActivity = void 0;
3375
+ resetStreamBlocks();
3376
+ liveTools.clear();
3377
+ sending = false;
3378
+ renaming = false;
3379
+ if (updateHistory) {
3380
+ history.pushState(null, "", sessionPath(id));
3381
+ }
3382
+ setPromptValue("");
3383
+ elements.sessionTitle.textContent = "Loading\u2026";
3384
+ elements.sessionTitle.title = "Session title is loading";
3385
+ elements.sessionTitle.setAttribute("aria-label", "Session title is loading");
3386
+ setWorkspace("", void 0);
3387
+ setContextValue(elements.sessionModel, "");
3388
+ elements.sessionModel.setAttribute("aria-label", "Model and thinking level are loading.");
3389
+ updateSessionUsage(null);
3390
+ renderEmpty("Loading conversation", "Reading the saved Pi session\u2026");
3391
+ updateControls();
3392
+ try {
3393
+ const response = await api(`/api/sessions/${encodeURIComponent(id)}`);
3394
+ if (currentSessionId !== id) {
3395
+ return;
3396
+ }
3397
+ currentSession = response.session;
3398
+ applyRuntimeState(response.runtime);
3399
+ updateSessionHeading();
3400
+ setWorkspace(response.session.cwd, response.session.gitContext);
3401
+ renderConversation(response.session, response.runtime);
3402
+ connectEvents(id);
3403
+ if (window.matchMedia("(hover: hover) and (pointer: fine)").matches) {
3404
+ elements.prompt.focus();
3405
+ }
3406
+ } catch (error) {
3407
+ if (currentSessionId !== id) {
3408
+ return;
3409
+ }
3410
+ appendError(readableError(error));
3411
+ setConnection("Unavailable", "error");
3412
+ }
3413
+ }
3414
+ async function renameCurrentSession() {
3415
+ if (!currentSessionId || renaming) {
3416
+ return;
3417
+ }
3418
+ const value = window.prompt("Session title (leave blank to clear)", currentNativeName() ?? "");
3419
+ if (value === null) {
3420
+ return;
3421
+ }
3422
+ const id = currentSessionId;
3423
+ renaming = true;
3424
+ updateControls();
3425
+ try {
3426
+ const response = await api(
3427
+ `/api/sessions/${encodeURIComponent(id)}/name`,
3428
+ {
3429
+ method: "PUT",
3430
+ headers: { "content-type": "application/json" },
3431
+ body: JSON.stringify({ name: value })
3432
+ }
3433
+ );
3434
+ if (currentSessionId !== id) {
3435
+ return;
3436
+ }
3437
+ applyRuntimeState(response.state);
3438
+ applyCurrentSessionName(response.name ?? void 0);
3439
+ } catch (error) {
3440
+ if (currentSessionId === id) {
3441
+ appendError(`Could not rename session: ${readableError(error)}`);
3442
+ }
3443
+ } finally {
3444
+ renaming = false;
3445
+ updateControls();
3446
+ }
3447
+ }
3448
+ async function sendMessage() {
3449
+ if (!currentSessionId || sending) {
3450
+ return;
3451
+ }
3452
+ const message = elements.prompt.value;
3453
+ if (!message.trim()) {
3454
+ return;
3455
+ }
3456
+ const id = currentSessionId;
3457
+ const pendingExtensionRequest = extensionUI.pending[0];
3458
+ const previousFirstMessage = currentSession?.firstMessage;
3459
+ const shouldUpdateFirstMessage = Boolean(currentSession && !currentSession.firstMessage.trim());
3460
+ if (currentSession && shouldUpdateFirstMessage) {
3461
+ currentSession.firstMessage = message;
3462
+ updateSessionHeading();
3463
+ }
3464
+ const activatedTurnAnchor = !elements.transcript.classList.contains("has-submitted-turn-anchor");
3465
+ const previousSubmittedTurnAnchor = submittedTurnAnchor;
3466
+ setSubmittedTurnAnchor(true);
3467
+ elements.transcript.querySelector(".empty-state")?.remove();
3468
+ if (!currentRuntime?.isWorking) {
3469
+ liveActivity = void 0;
3470
+ resetStreamBlocks();
3471
+ }
3472
+ const optimistic = createMessage({ role: "user", content: message });
3473
+ optimistic.dataset.optimistic = "true";
3474
+ optimisticSubmission = { sessionId: id, message, root: optimistic };
3475
+ submittedTurnAnchor = { sessionId: id, message, root: optimistic, needsAlignment: true };
3476
+ elements.transcript.append(optimistic);
3477
+ updateSubmittedTurnRunway();
3478
+ optimistic.scrollIntoView({ block: "start" });
3479
+ setPromptValue("");
3480
+ sending = true;
3481
+ updateControls();
3482
+ eventStream.ensureConnected();
3483
+ try {
3484
+ if (pendingExtensionRequest) {
3485
+ await respondToExtensionUI(pendingExtensionRequest, { cancelled: true }, false);
3486
+ if (currentSessionId !== id) {
3487
+ return;
3488
+ }
3489
+ }
3490
+ const response = await api(
3491
+ `/api/sessions/${encodeURIComponent(id)}/messages`,
3492
+ {
3493
+ method: "POST",
3494
+ headers: { "content-type": "application/json" },
3495
+ body: JSON.stringify({ message })
3496
+ }
3497
+ );
3498
+ if (currentSessionId !== id) {
3499
+ return;
3500
+ }
3501
+ applyRuntimeState(response.state);
3502
+ if (response.state.isWorking) {
3503
+ ensureLiveActivity();
3504
+ }
3505
+ void reconcileSession();
3506
+ } catch (error) {
3507
+ optimistic.remove();
3508
+ if (optimisticSubmission?.root === optimistic) {
3509
+ optimisticSubmission = void 0;
3510
+ }
3511
+ if (currentSessionId === id) {
3512
+ submittedTurnAnchor = previousSubmittedTurnAnchor;
3513
+ if (activatedTurnAnchor) {
3514
+ setSubmittedTurnAnchor(false);
3515
+ } else {
3516
+ updateSubmittedTurnRunway();
3517
+ }
3518
+ if (currentSession && shouldUpdateFirstMessage) {
3519
+ currentSession.firstMessage = previousFirstMessage ?? "";
3520
+ updateSessionHeading();
3521
+ }
3522
+ setPromptValue(message);
3523
+ appendError(readableError(error));
3524
+ void reconcileSession();
3525
+ }
3526
+ } finally {
3527
+ sending = false;
3528
+ updateControls();
3529
+ }
3530
+ }
3531
+ async function removePendingSteering(index, message) {
3532
+ if (!currentSessionId || !currentRuntime || sending) {
3533
+ return;
3534
+ }
3535
+ const id = currentSessionId;
3536
+ const expectedQueue = copyMessageQueue(currentRuntime.queue);
3537
+ const nextQueue = withoutSteeringMessage(expectedQueue, index, message);
3538
+ if (!nextQueue) {
3539
+ void reconcileSession();
3540
+ return;
3541
+ }
3542
+ sending = true;
3543
+ discardingQueue = true;
3544
+ dequeuedSteering = [];
3545
+ patchRuntimeState({
3546
+ pendingMessageCount: nextQueue.steering.length + nextQueue.followUp.length,
3547
+ queue: nextQueue
3548
+ });
3549
+ updateControls();
3550
+ try {
3551
+ const response = await api(`/api/sessions/${encodeURIComponent(id)}/pending-steering`, {
3552
+ method: "DELETE",
3553
+ headers: { "content-type": "application/json" },
3554
+ body: JSON.stringify({ index, message, queue: expectedQueue.steering })
3555
+ });
3556
+ if (currentSessionId !== id) {
3557
+ return;
3558
+ }
3559
+ applyRuntimeState(response.state);
3560
+ await reconcileSession();
3561
+ } catch (error) {
3562
+ if (currentSessionId === id) {
3563
+ appendError(`Could not remove pending message: ${readableError(error)}`);
3564
+ await reconcileSession();
3565
+ }
3566
+ } finally {
3567
+ sending = false;
3568
+ discardingQueue = false;
3569
+ renderPendingQueue();
3570
+ updateControls();
3571
+ }
3572
+ }
3573
+ async function abortRun() {
3574
+ if (!currentSessionId || sending) {
3575
+ return;
3576
+ }
3577
+ const id = currentSessionId;
3578
+ sending = true;
3579
+ discardingQueue = true;
3580
+ dequeuedSteering = [];
3581
+ patchRuntimeState({ pendingMessageCount: 0, queue: { steering: [], followUp: [] } });
3582
+ updateControls();
3583
+ try {
3584
+ const response = await api(`/api/sessions/${encodeURIComponent(id)}/abort`, {
3585
+ method: "POST",
3586
+ headers: { "content-type": "application/json" },
3587
+ body: "{}"
3588
+ });
3589
+ if (currentSessionId !== id) {
3590
+ return;
3591
+ }
3592
+ if (response.restoredMessages.length > 0) {
3593
+ setPromptValue(response.restoredMessages.join("\n\n"));
3594
+ }
3595
+ if (liveActivity) {
3596
+ setActivityAborted(liveActivity);
3597
+ }
3598
+ await reconcileSession();
3599
+ } catch (error) {
3600
+ if (currentSessionId === id) {
3601
+ appendError(readableError(error));
3602
+ void reconcileSession();
3603
+ }
3604
+ } finally {
3605
+ sending = false;
3606
+ discardingQueue = false;
3607
+ updateControls();
3608
+ }
3609
+ }
3610
+ var submittedTurnRunwayObserver = new MutationObserver(scheduleSubmittedTurnRunwayUpdate);
3611
+ submittedTurnRunwayObserver.observe(elements.transcript, {
3612
+ attributeFilter: ["open"],
3613
+ attributes: true,
3614
+ characterData: true,
3615
+ childList: true,
3616
+ subtree: true
3617
+ });
3618
+ elements.composer.addEventListener("submit", (event) => {
3619
+ event.preventDefault();
3620
+ void sendMessage();
3621
+ });
3622
+ elements.prompt.addEventListener("input", () => {
3623
+ dismissedSlashCompletionValue = void 0;
3624
+ resizePrompt();
3625
+ renderSlashCompletion(true);
3626
+ });
3627
+ elements.prompt.addEventListener("keydown", (event) => {
3628
+ if (slashCompletion && !event.isComposing) {
3629
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
3630
+ event.preventDefault();
3631
+ slashCompletion = moveSlashCompletionSelection(slashCompletion, event.key === "ArrowDown" ? 1 : -1);
3632
+ renderSlashCompletion();
3633
+ return;
3634
+ }
3635
+ if (event.key === "Tab") {
3636
+ event.preventDefault();
3637
+ applySelectedSlashCompletion(false);
3638
+ return;
3639
+ }
3640
+ if (event.key === "Enter" && !event.shiftKey) {
3641
+ event.preventDefault();
3642
+ applySelectedSlashCompletion(true);
3643
+ return;
3644
+ }
3645
+ if (event.key === "Escape") {
3646
+ event.preventDefault();
3647
+ closeSlashCompletion(true);
3648
+ return;
3649
+ }
3650
+ }
3651
+ if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
3652
+ event.preventDefault();
3653
+ void sendMessage();
3654
+ }
3655
+ });
3656
+ elements.abort.addEventListener("click", () => void abortRun());
3657
+ elements.sessionTitle.addEventListener("click", () => void renameCurrentSession());
3658
+ elements.sessionContextToggle.addEventListener("click", () => {
3659
+ setSessionContextCollapsed(!elements.sessionContext.classList.contains("is-collapsed"));
3660
+ });
3661
+ window.addEventListener("popstate", () => {
3662
+ const route = routeFromLocation();
3663
+ if (route) {
3664
+ void selectSession(route, false);
3665
+ } else {
3666
+ location.reload();
3667
+ }
3668
+ });
3669
+ document.addEventListener("visibilitychange", () => {
3670
+ if (document.visibilityState !== "visible" || !currentSessionId) {
3671
+ return;
3672
+ }
3673
+ eventStream.ensureConnected();
3674
+ void reconcileSession();
3675
+ });
3676
+ window.addEventListener("online", () => {
3677
+ if (!currentSessionId) {
3678
+ return;
3679
+ }
3680
+ eventStream.reconnectNow();
3681
+ void reconcileSession();
3682
+ });
3683
+ window.addEventListener("resize", () => {
3684
+ resizePrompt();
3685
+ scheduleSubmittedTurnRunwayUpdate();
3686
+ });
3687
+ function routeFromLocation() {
3688
+ const match = /^\/sessions\/([^/]+)\/?$/.exec(location.pathname);
3689
+ if (!match?.[1]) {
3690
+ return void 0;
3691
+ }
3692
+ try {
3693
+ return decodeURIComponent(match[1]);
3694
+ } catch {
3695
+ return void 0;
3696
+ }
3697
+ }
3698
+ var requestedSession = routeFromLocation();
3699
+ if (requestedSession) {
3700
+ void selectSession(requestedSession, false);
3701
+ } else {
3702
+ location.assign("/");
3703
+ }