neko-harness 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/neko.js CHANGED
@@ -79,7 +79,7 @@ function updateAction(input) {
79
79
  return "install";
80
80
  return "none";
81
81
  }
82
- var RUNNING_VERSION = "0.3.1", APPLICATION_PROTOCOL = 4, ApplicationProtocolError;
82
+ var RUNNING_VERSION = "0.3.2", APPLICATION_PROTOCOL = 4, ApplicationProtocolError;
83
83
  var init_application_version = __esm(() => {
84
84
  ApplicationProtocolError = class ApplicationProtocolError extends Error {
85
85
  constructor() {
@@ -846,6 +846,51 @@ function toolResultText(content) {
846
846
  return content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text ?? "").join(`
847
847
  `);
848
848
  }
849
+ function countDiffLines(diff) {
850
+ let added = 0;
851
+ let removed = 0;
852
+ for (const line of diff.split(`
853
+ `)) {
854
+ if (line.startsWith("+") && !line.startsWith("+++"))
855
+ added++;
856
+ else if (line.startsWith("-") && !line.startsWith("---"))
857
+ removed++;
858
+ }
859
+ return { added, removed };
860
+ }
861
+ function editResultDiff(details) {
862
+ if (typeof details !== "object" || details === null)
863
+ return null;
864
+ const diff = details.diff;
865
+ return typeof diff === "string" ? diff : null;
866
+ }
867
+ function synthesizedWriteDiff(args) {
868
+ const record = args ?? {};
869
+ if (typeof record.content !== "string")
870
+ return null;
871
+ const content = record.content;
872
+ const shown = [];
873
+ let offset = 0;
874
+ let bytes = 0;
875
+ while (offset < content.length && shown.length < WRITE_DIFF_MAX_LINES) {
876
+ const newline = content.indexOf(`
877
+ `, offset);
878
+ const end = newline === -1 ? content.length : newline;
879
+ const overhead = shown.length === 0 ? 2 : 3;
880
+ const remaining = WRITE_DIFF_MAX_BYTES - bytes - overhead;
881
+ if (end - offset > remaining)
882
+ break;
883
+ const line = content.slice(offset, end);
884
+ const lineBytes = Buffer.byteLength(line, "utf8");
885
+ if (lineBytes > remaining)
886
+ break;
887
+ shown.push(`+ ${line}`);
888
+ bytes += lineBytes + overhead;
889
+ offset = newline === -1 ? content.length : end + 1;
890
+ }
891
+ return { diff: shown.join(`
892
+ `), added: shown.length, removed: 0, truncated: offset < content.length };
893
+ }
849
894
  function totalUsage(state) {
850
895
  const total = {
851
896
  input: 0,
@@ -878,6 +923,8 @@ function projectChatView(view, modelLabel, options = {}) {
878
923
  if (message.role !== "toolResult")
879
924
  continue;
880
925
  const diagnostics = entry.data?.diagnostics ?? [];
926
+ const diff = message.toolName === "edit" ? editResultDiff(message.details) : null;
927
+ const counts = diff === null ? null : countDiffLines(diff);
881
928
  results.set(message.toolCallId, {
882
929
  type: "tool",
883
930
  key: `t${message.toolCallId}`,
@@ -894,7 +941,10 @@ function projectChatView(view, modelLabel, options = {}) {
894
941
  ].filter(Boolean).join(`
895
942
  `),
896
943
  durationMs: message.durationMs ?? null,
897
- note: null
944
+ note: null,
945
+ diff,
946
+ diffAdded: counts?.added ?? null,
947
+ diffRemoved: counts?.removed ?? null
898
948
  });
899
949
  }
900
950
  }
@@ -952,6 +1002,7 @@ function projectChatView(view, modelLabel, options = {}) {
952
1002
  } else {
953
1003
  const summary = summarizeToolCall(block.name, block.arguments);
954
1004
  const slot = live.tools?.find((s) => s.callId === block.id);
1005
+ const synthesized = block.name === "write" ? synthesizedWriteDiff(block.arguments) : null;
955
1006
  items.push({
956
1007
  type: "tool",
957
1008
  key: `t${block.id}`,
@@ -964,7 +1015,11 @@ function projectChatView(view, modelLabel, options = {}) {
964
1015
  output: slot?.output ?? null,
965
1016
  result: null,
966
1017
  durationMs: null,
967
- note: ran ? null : "Not run: response interrupted."
1018
+ note: ran ? null : "Not run: response interrupted.",
1019
+ diff: synthesized?.diff ?? null,
1020
+ diffAdded: synthesized?.added ?? null,
1021
+ diffRemoved: synthesized?.removed ?? null,
1022
+ diffTruncated: synthesized?.truncated ?? false
968
1023
  });
969
1024
  }
970
1025
  }
@@ -1012,7 +1067,17 @@ function projectChatView(view, modelLabel, options = {}) {
1012
1067
  }
1013
1068
  function withArgs(item, name, args) {
1014
1069
  const summary = summarizeToolCall(name, args);
1015
- return { ...item, name, summary: summary.args, detail: summary.detail ?? null };
1070
+ const synthesized = name === "write" ? synthesizedWriteDiff(args) : null;
1071
+ return {
1072
+ ...item,
1073
+ name,
1074
+ summary: summary.args,
1075
+ detail: summary.detail ?? null,
1076
+ diff: synthesized?.diff ?? item.diff,
1077
+ diffAdded: synthesized?.added ?? item.diffAdded,
1078
+ diffRemoved: synthesized?.removed ?? item.diffRemoved,
1079
+ diffTruncated: synthesized?.truncated ?? false
1080
+ };
1016
1081
  }
1017
1082
  function assistantItem(message, id) {
1018
1083
  let thinking = "";
@@ -1065,13 +1130,18 @@ ${block.text}`;
1065
1130
  if (block.type === "toolCall") {
1066
1131
  const slot = live.tools?.find((candidate) => candidate.callId === block.id);
1067
1132
  const summary = summarizeToolCall(block.name, block.arguments);
1133
+ const synthesized = block.name === "write" ? synthesizedWriteDiff(block.arguments) : null;
1068
1134
  toolCalls.push({
1069
1135
  callId: block.id,
1070
1136
  name: block.name,
1071
1137
  summary: summary.args,
1072
1138
  detail: summary.detail ?? null,
1073
1139
  phase: slot === undefined || slot.status === "pending" ? "pending" : slot.status,
1074
- output: slot?.status === "running" ? slot.output ?? null : null
1140
+ output: slot?.status === "running" ? slot.output ?? null : null,
1141
+ diff: synthesized?.diff ?? null,
1142
+ diffAdded: synthesized?.added ?? null,
1143
+ diffRemoved: synthesized?.removed ?? null,
1144
+ diffTruncated: synthesized?.truncated ?? false
1075
1145
  });
1076
1146
  }
1077
1147
  }
@@ -1091,10 +1161,12 @@ function contextTokens(entries) {
1091
1161
  }
1092
1162
  return null;
1093
1163
  }
1164
+ var WRITE_DIFF_MAX_LINES = 2000, WRITE_DIFF_MAX_BYTES;
1094
1165
  var init_projection = __esm(() => {
1095
1166
  init_image_prompt();
1096
1167
  init_input();
1097
1168
  init_workspace();
1169
+ WRITE_DIFF_MAX_BYTES = 64 * 1024;
1098
1170
  });
1099
1171
 
1100
1172
  // packages/core/src/prompt/frontmatter.ts
@@ -4049,6 +4121,60 @@ function compactInstructions(text) {
4049
4121
  return match ? match[1]?.trim() ?? "" : null;
4050
4122
  }
4051
4123
 
4124
+ // packages/core/src/conversation-items.ts
4125
+ function userText2(item) {
4126
+ if (item.skill === undefined)
4127
+ return item.text;
4128
+ return item.skill.args === "" ? `/skill:${item.skill.name}` : `/skill:${item.skill.name} ${item.skill.args}`;
4129
+ }
4130
+ function toolStatus(item) {
4131
+ return item.phase !== "done" ? item.phase : item.isError ? "error" : "ok";
4132
+ }
4133
+ function toolOutput(item) {
4134
+ return (item.phase === "done" ? item.result : item.output) ?? "";
4135
+ }
4136
+ function imageLabel(image) {
4137
+ const size = image.width > 0 && image.height > 0 ? ` \xB7 ${image.width}\xD7${image.height}` : "";
4138
+ return `${image.name} \xB7 ${image.mimeType}${size}`;
4139
+ }
4140
+ function formatDuration(ms) {
4141
+ return ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;
4142
+ }
4143
+ function oneLine(text) {
4144
+ return text.replace(/\s+/g, " ").trim();
4145
+ }
4146
+ var FALLBACK_EXPORT_TITLE = "neko-session";
4147
+
4148
+ // packages/core/src/input-history.ts
4149
+ function promptHistory(items) {
4150
+ const entries = [];
4151
+ for (const item of items) {
4152
+ if (item.type !== "user" || item.subagentRoundId !== undefined)
4153
+ continue;
4154
+ const text = userText2(item).trim();
4155
+ if (text === "" || entries.at(-1) === text)
4156
+ continue;
4157
+ entries.push(text);
4158
+ }
4159
+ return entries.reverse().slice(0, INPUT_HISTORY_LIMIT);
4160
+ }
4161
+ var INPUT_HISTORY_LIMIT = 100;
4162
+ var init_input_history = () => {};
4163
+
4164
+ // packages/core/src/session-display.ts
4165
+ function relativeTime(at, now, language = "en") {
4166
+ const minutes = Math.floor(Math.max(0, now - at) / 60000);
4167
+ if (minutes < 1)
4168
+ return language === "zh" ? "\u521A\u521A" : "now";
4169
+ const hours = Math.floor(minutes / 60), days = Math.floor(hours / 24);
4170
+ if (days >= 30)
4171
+ return new Date(at).toLocaleDateString(language === "zh" ? "zh-CN" : "en-GB");
4172
+ const value = days || hours || minutes;
4173
+ const unit = days ? ["\u5929", "d"] : hours ? ["\u5C0F\u65F6", "h"] : ["\u5206\u949F", "m"];
4174
+ return language === "zh" ? `${value} ${unit[0]}\u524D` : `${value}${unit[1]}`;
4175
+ }
4176
+ var sessionName = (session, empty = "New session") => session.title || session.firstPromptPreview || empty, messageTime = (session) => session.lastMessageAt ?? session.createdAt, byMessage = (a, b) => messageTime(b) - messageTime(a) || Number(b.id) - Number(a.id), byVisited = (a, b) => b.lastUsedAt - a.lastUsedAt || Number(b.id) - Number(a.id);
4177
+
4052
4178
  // packages/gateway/src/contract.ts
4053
4179
  import { method, remote } from "@earendil-works/chord";
4054
4180
  import { Type as Type4 } from "typebox";
@@ -4092,7 +4218,11 @@ var init_contract = __esm(() => {
4092
4218
  summary: str,
4093
4219
  detail: nullableString,
4094
4220
  phase,
4095
- output: nullableString
4221
+ output: nullableString,
4222
+ diff: nullableString,
4223
+ diffAdded: Type4.Union([num, nil]),
4224
+ diffRemoved: Type4.Union([num, nil]),
4225
+ diffTruncated: Type4.Optional(bool)
4096
4226
  });
4097
4227
  DelegationSchema = Type4.Object({
4098
4228
  parentId: integer,
@@ -4200,7 +4330,11 @@ var init_contract = __esm(() => {
4200
4330
  output: nullableString,
4201
4331
  result: nullableString,
4202
4332
  durationMs: Type4.Union([num, nil]),
4203
- note: nullableString
4333
+ note: nullableString,
4334
+ diff: nullableString,
4335
+ diffAdded: Type4.Union([num, nil]),
4336
+ diffRemoved: Type4.Union([num, nil]),
4337
+ diffTruncated: Type4.Optional(bool)
4204
4338
  }),
4205
4339
  Type4.Object({ type: Type4.Literal("system"), order: Type4.Optional(num), key: str, id: integer, text: str })
4206
4340
  ])),
@@ -5026,8 +5160,8 @@ var init_palette = __esm(() => {
5026
5160
  codeFg: { fg: "#C0CAF5" },
5027
5161
  border: { fg: "#737DA2" },
5028
5162
  borderMuted: { fg: "#545E7C" },
5029
- diffAdded: { fg: "#9ECE6A" },
5030
- diffRemoved: { fg: "#F7768E" },
5163
+ diffAdded: { fg: "#9ECE6A", bg: "#232C32" },
5164
+ diffRemoved: { fg: "#F7768E", bg: "#302735" },
5031
5165
  diffContext: { fg: "#9AA5CE" },
5032
5166
  syntaxComment: { fg: "#8993B3", italic: true },
5033
5167
  syntaxKeyword: { fg: "#BB9AF7", bold: true },
@@ -5061,8 +5195,8 @@ var init_palette = __esm(() => {
5061
5195
  codeFg: { fg: sakura.s800 },
5062
5196
  border: { fg: ink.s300 },
5063
5197
  borderMuted: { fg: ink.s200 },
5064
- diffAdded: { fg: "#1A7F37" },
5065
- diffRemoved: { fg: sakura.s800 },
5198
+ diffAdded: { fg: "#1A7F37", bg: "#E4F3E8" },
5199
+ diffRemoved: { fg: sakura.s800, bg: "#FBE7EC" },
5066
5200
  diffContext: { fg: ink.s400 },
5067
5201
  syntaxComment: { fg: ink.s600, italic: true },
5068
5202
  syntaxKeyword: { fg: sakura.s800 },
@@ -5155,6 +5289,10 @@ function getActiveThemeMode() {
5155
5289
  function delegate(name) {
5156
5290
  return (text) => activeTheme[name](text);
5157
5291
  }
5292
+ function diffBackgroundAnsi(kind) {
5293
+ const style = (activeMode === "dark" ? DARK_PALETTE : LIGHT_PALETTE)[kind === "added" ? "diffAdded" : "diffRemoved"];
5294
+ return backgroundAnsi(parseColor(style.bg), getTerminalColorMode());
5295
+ }
5158
5296
  var darkTheme, lightTheme, THEMES, activeMode = "dark", activeTheme, theme, sgr = (attrs) => (text) => styleText(text, {
5159
5297
  ...attrs.bold !== undefined ? { bold: attrs.bold } : {},
5160
5298
  ...attrs.italic !== undefined ? { italic: attrs.italic } : {},
@@ -14579,7 +14717,7 @@ function solidBlock(lines, fullWidth) {
14579
14717
  const max = Math.max(fullWidth ?? 0, ...lines.map((line) => line.width));
14580
14718
  return lines.map((line) => theme.codeBg(line.styled + " ".repeat(Math.max(0, max - line.width))));
14581
14719
  }
14582
- function renderHighlighted(html, fullWidth) {
14720
+ function htmlToSegmentLines(html) {
14583
14721
  const segments = [];
14584
14722
  const scopes = [];
14585
14723
  let textBuffer = "";
@@ -14632,25 +14770,31 @@ function renderHighlighted(html, fullWidth) {
14632
14770
  }
14633
14771
  flushText();
14634
14772
  const lines = [];
14635
- let current = "";
14636
- let currentWidth = 0;
14773
+ let current = [];
14637
14774
  for (const segment of segments) {
14638
14775
  const parts = segment.text.split(`
14639
14776
  `);
14640
14777
  for (const [i, part] of parts.entries()) {
14641
14778
  if (i > 0) {
14642
- lines.push({ styled: current, width: currentWidth });
14643
- current = "";
14644
- currentWidth = 0;
14779
+ lines.push(current);
14780
+ current = [];
14645
14781
  }
14646
14782
  if (part === "")
14647
14783
  continue;
14648
- currentWidth += visibleWidth(part);
14649
- current += segment.slot === "plain" ? theme.codeFg(part) : theme[segment.slot](part);
14784
+ current.push({ slot: segment.slot, text: part });
14650
14785
  }
14651
14786
  }
14652
- lines.push({ styled: current, width: currentWidth });
14653
- return solidBlock(lines, fullWidth);
14787
+ lines.push(current);
14788
+ return lines;
14789
+ }
14790
+ function styleSegmentLine(segments) {
14791
+ return {
14792
+ styled: segments.map((s) => s.slot === "plain" ? theme.codeFg(s.text) : theme[s.slot](s.text)).join(""),
14793
+ width: segments.reduce((total, s) => total + visibleWidth(s.text), 0)
14794
+ };
14795
+ }
14796
+ function renderHighlighted(html, fullWidth) {
14797
+ return solidBlock(htmlToSegmentLines(html).map(styleSegmentLine), fullWidth);
14654
14798
  }
14655
14799
  function normalizeLang(lang) {
14656
14800
  if (lang === undefined)
@@ -14658,6 +14802,28 @@ function normalizeLang(lang) {
14658
14802
  const lowered = lang.trim().toLowerCase();
14659
14803
  return LANG_ALIASES[lowered] ?? lowered;
14660
14804
  }
14805
+ function highlightCodeToSegments(code, lang) {
14806
+ const normalized = normalizeLang(lang);
14807
+ if (normalized === "" || core_default.getLanguage(normalized) === undefined)
14808
+ return null;
14809
+ try {
14810
+ return htmlToSegmentLines(core_default.highlight(code, { language: normalized }).value);
14811
+ } catch {
14812
+ return null;
14813
+ }
14814
+ }
14815
+ function languageForPath(path) {
14816
+ if (path === undefined)
14817
+ return;
14818
+ const base = path.slice(path.lastIndexOf("/") + 1).toLowerCase();
14819
+ const dot = base.lastIndexOf(".");
14820
+ if (dot <= 0)
14821
+ return;
14822
+ const ext = base.slice(dot + 1);
14823
+ if (ext === "" || core_default.getLanguage(ext) === undefined)
14824
+ return;
14825
+ return ext;
14826
+ }
14661
14827
  function highlightCodeToAnsiLines(code, lang, fullWidth) {
14662
14828
  const normalized = normalizeLang(lang);
14663
14829
  if (normalized !== "" && core_default.getLanguage(normalized) !== undefined) {
@@ -14977,147 +15143,2027 @@ var init_approval_dock = __esm(() => {
14977
15143
  init_theme();
14978
15144
  });
14979
15145
 
14980
- // packages/tui/src/components/assistant-message.ts
14981
- import { Container, Markdown, MouseRegion, Spacer, Text as Text2 } from "@earendil-works/pi-tui";
14982
- var THINKING_COLLAPSED_LABEL = "\u2727 Thinking\u2026 (click to expand)", AssistantMessageComponent;
14983
- var init_assistant_message = __esm(() => {
14984
- init_theme();
14985
- AssistantMessageComponent = class AssistantMessageComponent extends Container {
14986
- #renderTheme = getActiveThemeMode();
14987
- #lastContent;
14988
- #isStreaming = false;
14989
- #thinkingExpanded = false;
14990
- #renderWidth = 80;
14991
- constructor(content, isStreaming = false) {
14992
- super();
14993
- if (content !== undefined)
14994
- this.updateContent(content, isStreaming);
14995
- }
14996
- render(width) {
14997
- if (this.#renderTheme !== getActiveThemeMode()) {
14998
- this.#renderTheme = getActiveThemeMode();
14999
- this.#rebuild();
15000
- }
15001
- this.#renderWidth = width;
15002
- return super.render(width);
15146
+ // node_modules/marked/lib/marked.esm.js
15147
+ function I() {
15148
+ return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
15149
+ }
15150
+ function W(l) {
15151
+ P = l;
15152
+ }
15153
+ function C(l) {
15154
+ let e = [];
15155
+ return (t) => {
15156
+ let n = Math.max(0, Math.min(3, t - 1)), s = e[n];
15157
+ return s || (s = l(n), e[n] = s), s;
15158
+ };
15159
+ }
15160
+ function h(l, e = "") {
15161
+ let t = typeof l == "string" ? l : l.source, n = { replace: (s, r) => {
15162
+ let o = typeof r == "string" ? r : r.source;
15163
+ return o = o.replace(x.caret, "$1"), t = t.replace(s, o), n;
15164
+ }, getRegex: () => new RegExp(t, e) };
15165
+ return n;
15166
+ }
15167
+ function O(l, e) {
15168
+ if (e) {
15169
+ if (x.escapeTest.test(l))
15170
+ return l.replace(x.escapeReplace, Re);
15171
+ } else if (x.escapeTestNoEncode.test(l))
15172
+ return l.replace(x.escapeReplaceNoEncode, Re);
15173
+ return l;
15174
+ }
15175
+ function Te(l) {
15176
+ return l.replace(x.numericCharacterReference, (e, t, n) => {
15177
+ let s = t === undefined ? Number.parseInt(n, 16) : Number.parseInt(t, 10);
15178
+ return s === 0 || s > 1114111 || s >= 55296 && s <= 57343 ? "\uFFFD" : String.fromCodePoint(s);
15179
+ });
15180
+ }
15181
+ function re(l) {
15182
+ try {
15183
+ l = encodeURI(l).replace(x.percentDecode, "%");
15184
+ } catch {
15185
+ return null;
15186
+ }
15187
+ return l;
15188
+ }
15189
+ function se(l, e) {
15190
+ let t = l.replace(x.findPipe, (r, o, i) => {
15191
+ let u = false, a = o;
15192
+ for (;--a >= 0 && i[a] === "\\"; )
15193
+ u = !u;
15194
+ return u ? "|" : " |";
15195
+ }), n = t.split(x.splitPipe), s = 0;
15196
+ if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e)
15197
+ if (n.length > e)
15198
+ n.splice(e);
15199
+ else
15200
+ for (;n.length < e; )
15201
+ n.push("");
15202
+ for (;s < n.length; s++)
15203
+ n[s] = n[s].trim().replace(x.slashPipe, "|");
15204
+ return n;
15205
+ }
15206
+ function L(l, e, t) {
15207
+ let n = l.length;
15208
+ if (n === 0)
15209
+ return "";
15210
+ let s = 0;
15211
+ for (;s < n; ) {
15212
+ let r = l.charAt(n - s - 1);
15213
+ if (r === e && !t)
15214
+ s++;
15215
+ else if (r !== e && t)
15216
+ s++;
15217
+ else
15218
+ break;
15219
+ }
15220
+ return l.slice(0, n - s);
15221
+ }
15222
+ function ie(l) {
15223
+ let e = l.split(`
15224
+ `), t = e.length - 1;
15225
+ for (;t >= 0 && x.blankLine.test(e[t]); )
15226
+ t--;
15227
+ return e.length - t <= 2 ? l : e.slice(0, t + 1).join(`
15228
+ `);
15229
+ }
15230
+ function q(l) {
15231
+ return l.trim().toLowerCase().toUpperCase().toLowerCase();
15232
+ }
15233
+ function oe(l, e) {
15234
+ if (l.indexOf(e[0]) === -1 && l.indexOf(e[1]) === -1)
15235
+ return -1;
15236
+ let t = 0;
15237
+ for (let n = 0;n < l.length; n++)
15238
+ if (l[n] === "\\")
15239
+ n++;
15240
+ else if (l[n] === e[0])
15241
+ t++;
15242
+ else if (l[n] === e[1] && (t--, t < 0))
15243
+ return n;
15244
+ return t > 0 ? -2 : -1;
15245
+ }
15246
+ function ae(l, e = 0) {
15247
+ let t = e, n = "";
15248
+ for (let s of l)
15249
+ if (s === "\t") {
15250
+ let r = 4 - t % 4;
15251
+ n += " ".repeat(r), t += r;
15252
+ } else
15253
+ n += s, t++;
15254
+ return n;
15255
+ }
15256
+ function Oe(l, e, t, n, s) {
15257
+ let r = e.href, o = e.title || null, i = l[1].replace(s.other.outputLinkReplace, "$1"), u = l[0].charAt(0) === "!";
15258
+ n.state.inLink = true;
15259
+ let a = n.state.linkEmitted, p = n.state.inRawBlock;
15260
+ n.state.linkEmitted = false;
15261
+ let c = n.inlineTokens(i), d = n.state.linkEmitted;
15262
+ if (n.state.linkEmitted = a, n.state.inLink = false, !u) {
15263
+ if (d) {
15264
+ n.state.inRawBlock = p;
15265
+ return;
15003
15266
  }
15004
- #highlightWidth() {
15005
- return Math.max(10, this.#renderWidth - 4);
15267
+ n.state.linkEmitted = true;
15268
+ }
15269
+ return { type: u ? "image" : "link", raw: t, href: r, title: o, text: i, tokens: c };
15270
+ }
15271
+ function Pt(l, e, t) {
15272
+ let n = l.match(t.other.indentCodeCompensation);
15273
+ if (n === null)
15274
+ return e;
15275
+ let s = n[1];
15276
+ return e.split(`
15277
+ `).map((r) => {
15278
+ let o = r.match(t.other.beginningSpace);
15279
+ if (o === null)
15280
+ return r;
15281
+ let [i] = o;
15282
+ return r.slice(Math.min(i.length, s.length));
15283
+ }).join(`
15284
+ `);
15285
+ }
15286
+ function we(l, e, t, n) {
15287
+ if (!e.includes("<"))
15288
+ return false;
15289
+ for (let s = 0;s < e.length; s++) {
15290
+ if (e[s] === "\\") {
15291
+ s++;
15292
+ continue;
15006
15293
  }
15007
- updateContent(content, isStreaming = this.#isStreaming) {
15008
- this.#lastContent = content;
15009
- this.#isStreaming = isStreaming;
15010
- this.#rebuild();
15294
+ if (e[s] === "`") {
15295
+ let i = n.inline.code.exec(e.slice(s));
15296
+ if (i) {
15297
+ s += i[0].length - 1;
15298
+ continue;
15299
+ }
15011
15300
  }
15012
- setThinkingExpanded(expanded) {
15013
- this.#thinkingExpanded = expanded;
15014
- if (this.#lastContent !== undefined)
15015
- this.#rebuild();
15301
+ if (e[s] !== "<")
15302
+ continue;
15303
+ let r = l.slice(t + s), o = n.inline.tag.exec(r) || n.inline.autolink.exec(r);
15304
+ if (o) {
15305
+ if (o[0].length > e.length - s)
15306
+ return true;
15307
+ s += o[0].length - 1;
15016
15308
  }
15017
- #rebuild() {
15018
- const content = this.#lastContent;
15019
- this.clear();
15020
- if (content === undefined)
15021
- return;
15022
- if (content.thinking.trim() !== "") {
15023
- const expanded = this.#thinkingExpanded;
15024
- const thinkingComponent = expanded ? new Markdown(content.thinking.trim(), 1, 0, getMarkdownTheme(() => this.#highlightWidth()), {
15025
- color: theme.thinking,
15026
- italic: true
15027
- }) : new Text2(theme.thinking(THINKING_COLLAPSED_LABEL), 1, 0);
15028
- this.addChild(new MouseRegion(thinkingComponent, (event) => {
15029
- if (event.type !== "click" || event.button !== "left")
15030
- return;
15031
- this.setThinkingExpanded(!expanded);
15032
- return { handled: true };
15033
- }));
15034
- }
15035
- if (content.text.trim() !== "") {
15036
- this.addChild(new Markdown(content.text.trim(), 1, 0, getMarkdownTheme(() => this.#highlightWidth())));
15037
- }
15038
- if (content.note !== null) {
15039
- this.addChild(new Spacer(1));
15040
- this.addChild(new Text2(theme.error(content.note), 1, 0));
15309
+ }
15310
+ return false;
15311
+ }
15312
+ function k(l, e) {
15313
+ return E.parse(l, e);
15314
+ }
15315
+ function yt(...l) {
15316
+ return E.use(...l), k.defaults = E.defaults, W(k.defaults), k;
15317
+ }
15318
+ var P, A, _e, x, $e, Le, ze, G, Ae, J, he, de, Ee, V, Me, Y, Ie, Ce, N = "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", ee, Be, ke = (l) => h(V).replace("hr", G).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", l).replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", N).getRegex(), De, qe, ve, te, ue, Ze, He, Ge, Ne, ge, Qe, $, B, Q, je, Fe, fe, Ue, Ke, We, me, Xe, Je, Ve, Ye, xe = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)", et, tt, nt = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)", rt, st, it = "^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)", ot, at, lt = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)", ut, pt, ct, ht, dt, be, U, kt, gt, ft, pe, mt, xt, ce, bt, Rt, ne, Tt, X, Ot, j, D, wt, Re = (l) => wt[l], y = class {
15319
+ options;
15320
+ rules;
15321
+ lexer;
15322
+ constructor(e) {
15323
+ this.options = e || P;
15324
+ }
15325
+ space(e) {
15326
+ let t = this.rules.block.newline.exec(e);
15327
+ if (t && t[0].length > 0)
15328
+ return { type: "space", raw: t[0] };
15329
+ }
15330
+ code(e) {
15331
+ let t = this.rules.block.code.exec(e);
15332
+ if (t) {
15333
+ let n = this.options.pedantic ? t[0] : ie(t[0]), s = n.replace(this.rules.other.codeRemoveIndent, "");
15334
+ return { type: "code", raw: n, codeBlockStyle: "indented", text: s };
15335
+ }
15336
+ }
15337
+ fences(e) {
15338
+ let t = this.rules.block.fences.exec(e);
15339
+ if (t) {
15340
+ let n = t[0], s = Pt(n, t[3] || "", this.rules);
15341
+ return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: s };
15342
+ }
15343
+ }
15344
+ heading(e) {
15345
+ let t = this.rules.block.heading.exec(e);
15346
+ if (t) {
15347
+ let n = t[2].trim();
15348
+ if (this.rules.other.endingHash.test(n)) {
15349
+ let s = L(n, "#");
15350
+ (this.options.pedantic || !s || this.rules.other.endingSpaceTabChar.test(s)) && (n = s.trim());
15351
+ }
15352
+ return { type: "heading", raw: L(t[0], `
15353
+ `), depth: t[1].length, text: n, tokens: this.lexer.inline(n) };
15354
+ }
15355
+ }
15356
+ hr(e) {
15357
+ let t = this.rules.block.hr.exec(e);
15358
+ if (t)
15359
+ return { type: "hr", raw: L(t[0], `
15360
+ `) };
15361
+ }
15362
+ blockquote(e) {
15363
+ let t = this.rules.block.blockquote.exec(e);
15364
+ if (t) {
15365
+ let n = L(t[0], `
15366
+ `).split(`
15367
+ `), s = "", r = "", o = [];
15368
+ for (;n.length > 0; ) {
15369
+ let i = false, u = [], a;
15370
+ for (a = 0;a < n.length; a++)
15371
+ if (this.rules.other.blockquoteStart.test(n[a]))
15372
+ u.push(n[a]), i = true;
15373
+ else if (!i)
15374
+ u.push(n[a]);
15375
+ else
15376
+ break;
15377
+ n = n.slice(a);
15378
+ let p = u.join(`
15379
+ `), c = p.replace(this.rules.other.blockquoteSetextReplace, `
15380
+ $1`).replace(this.rules.other.blockquoteSetextReplace2, "");
15381
+ s = s ? `${s}
15382
+ ${p}` : p, r = r ? `${r}
15383
+ ${c}` : c;
15384
+ let d = this.lexer.state.top;
15385
+ if (this.lexer.state.top = true, this.lexer.blockTokens(c, o, true), this.lexer.state.top = d, n.length === 0)
15386
+ break;
15387
+ let m = o.at(-1);
15388
+ if (m?.type === "code")
15389
+ break;
15390
+ if (m?.type === "blockquote") {
15391
+ let b = m, g = n.join(`
15392
+ `), w = b.raw + `
15393
+ ` + g.replace(this.rules.other.blockquoteSetextReplace2, ""), f = this.blockquote(w);
15394
+ o[o.length - 1] = f;
15395
+ let M = w.substring(f.raw.length).replace(/^\n/, ""), v = M ? M.split(`
15396
+ `).length : 0, Z = v ? n.slice(0, -v) : n;
15397
+ Z.length > 0 && (s = `${s}
15398
+ ${Z.join(`
15399
+ `)}`), r = r.substring(0, r.length - b.text.length) + f.text;
15400
+ break;
15401
+ } else if (m?.type === "list") {
15402
+ let b = m, g = b.raw + `
15403
+ ` + n.join(`
15404
+ `), w = this.list(g);
15405
+ o[o.length - 1] = w, s = s.substring(0, s.length - m.raw.length) + w.raw, r = r.substring(0, r.length - b.raw.length) + w.raw, n = g.substring(o.at(-1).raw.length).split(`
15406
+ `);
15407
+ continue;
15408
+ }
15041
15409
  }
15410
+ return { type: "blockquote", raw: s, tokens: o, text: r };
15042
15411
  }
15043
- };
15044
- });
15045
-
15046
- // packages/tui/src/components/editor.ts
15047
- import {
15048
- CURSOR_MARKER,
15049
- Editor,
15050
- isKeyRelease,
15051
- isKeyRepeat,
15052
- matchesKey as matchesKey3,
15053
- stripTerminalSequences
15054
- } from "@earendil-works/pi-tui";
15055
- var BoundedEditor;
15056
- var init_editor = __esm(() => {
15057
- BoundedEditor = class BoundedEditor extends Editor {
15058
- maxRows = 7;
15059
- isImageReference = () => false;
15060
- onClearDraft;
15061
- #lastEscape = 0;
15062
- #completionEpoch = 0;
15063
- #completionProvider;
15064
- setAutocompleteProvider(provider) {
15065
- this.#completionEpoch++;
15066
- const wrapped = {
15067
- triggerCharacters: provider.triggerCharacters,
15068
- shouldTriggerFileCompletion: provider.shouldTriggerFileCompletion?.bind(provider),
15069
- getSuggestions: provider.getSuggestions.bind(provider),
15070
- applyCompletion: (...args) => {
15071
- const result = provider.applyCompletion(...args);
15072
- if (args[4].startsWith("@") && args[3].label.endsWith("/")) {
15073
- const epoch = this.#completionEpoch;
15074
- queueMicrotask(() => {
15075
- const cursor = this.getCursor();
15076
- if (epoch === this.#completionEpoch && this.getText() === result.lines.join(`
15077
- `) && cursor.line === result.cursorLine && cursor.col === result.cursorCol)
15078
- super.handleInput("\t");
15079
- });
15412
+ }
15413
+ list(e) {
15414
+ let t = this.rules.block.list.exec(e);
15415
+ if (t) {
15416
+ let n = t[1].trim(), s = n.length > 1, r = { type: "list", raw: "", ordered: s, start: s ? +n.slice(0, -1) : "", loose: false, items: [] };
15417
+ n = s ? `\\d{1,9}\\${n.slice(-1)}` : `\\${n}`, this.options.pedantic && (n = s ? n : "[*+-]");
15418
+ let o = this.rules.other.listItemRegex(n), i = false;
15419
+ for (;e; ) {
15420
+ let a = false, p = "", c = "";
15421
+ if (!(t = o.exec(e)) || this.rules.block.hr.test(e))
15422
+ break;
15423
+ p = t[0], e = e.substring(p.length);
15424
+ let d = t[2].split(`
15425
+ `, 1)[0], m = t[1].length, b = this.options.pedantic ? ae(d, m) : d.replace(this.rules.other.leadingSpaceTab, (M) => ae(M, m)), g = e.split(`
15426
+ `, 1)[0], w = !b.trim(), f = 0;
15427
+ if (this.options.pedantic ? (f = 2, c = b.trimStart()) : w ? f = m + 1 : (f = b.search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, c = b.slice(f), f += m), w && this.rules.other.blankLine.test(g) && (p += g + `
15428
+ `, e = e.substring(g.length + 1), a = true), !a) {
15429
+ let M = this.rules.other.nextBulletRegex(f), v = this.rules.other.hrRegex(f), Z = this.rules.other.fencesBeginRegex(f), le = this.rules.other.headingBeginRegex(f), Pe = this.rules.other.htmlBeginRegex(f), ye = this.rules.other.blockquoteBeginRegex(f);
15430
+ for (;e; ) {
15431
+ let K = e.split(`
15432
+ `, 1)[0], H;
15433
+ if (g = K, this.options.pedantic ? (g = g.replace(this.rules.other.listReplaceNesting, " "), H = g) : H = g.replace(this.rules.other.leadingSpaceTab, (Se) => Se.replace(this.rules.other.tabCharGlobal, " ")), Z.test(g) || le.test(g) || Pe.test(g) || ye.test(g) || M.test(g) || v.test(g))
15434
+ break;
15435
+ if (H.search(this.rules.other.nonSpaceChar) >= f || !g.trim())
15436
+ c += `
15437
+ ` + H.slice(f);
15438
+ else {
15439
+ if (w || b.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || Z.test(b) || le.test(b) || v.test(b))
15440
+ break;
15441
+ c += `
15442
+ ` + g;
15443
+ }
15444
+ w = !g.trim(), p += K + `
15445
+ `, e = e.substring(K.length + 1), b = H.slice(f);
15080
15446
  }
15081
- return result;
15082
15447
  }
15083
- };
15084
- this.#completionProvider = wrapped;
15085
- super.setAutocompleteProvider(wrapped);
15086
- }
15087
- resetEscapeSequence() {
15088
- this.#lastEscape = 0;
15448
+ 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;
15449
+ }
15450
+ let u = r.items.at(-1);
15451
+ if (u)
15452
+ u.raw = u.raw.trimEnd(), u.text = u.text.trimEnd();
15453
+ else
15454
+ return;
15455
+ r.raw = r.raw.trimEnd();
15456
+ for (let a of r.items)
15457
+ if (this.lexer.state.top = false, a.tokens = this.lexer.blockTokens(a.text, []), !r.loose) {
15458
+ let p = a.tokens.filter((d) => d.type === "space"), c = p.length > 0 && p.some((d) => this.rules.other.anyLine.test(d.raw));
15459
+ r.loose = c;
15460
+ }
15461
+ for (let a of r.items) {
15462
+ let p = a.tokens[0];
15463
+ if (a.task && (p?.type === "text" || p?.type === "paragraph")) {
15464
+ 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, "");
15465
+ for (let d = this.lexer.inlineQueue.length - 1;d >= 0; d--)
15466
+ if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[d].src)) {
15467
+ this.lexer.inlineQueue[d].src = this.lexer.inlineQueue[d].src.replace(this.rules.other.listReplaceTask, "");
15468
+ break;
15469
+ }
15470
+ let c = this.rules.other.listTaskCheckbox.exec(a.raw);
15471
+ if (c) {
15472
+ let d = { type: "checkbox", raw: c[0] + " ", checked: c[0] !== "[ ]" };
15473
+ a.checked = d.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 = d.raw + a.tokens[0].raw, a.tokens[0].text = d.raw + a.tokens[0].text, a.tokens[0].tokens.unshift(d)) : a.tokens.unshift({ type: "paragraph", raw: d.raw, text: d.raw, tokens: [d] }) : a.tokens.unshift(d);
15474
+ }
15475
+ } else
15476
+ a.task && (a.task = false);
15477
+ }
15478
+ if (r.loose)
15479
+ for (let a of r.items) {
15480
+ a.loose = true;
15481
+ for (let p of a.tokens)
15482
+ p.type === "text" && (p.type = "paragraph");
15483
+ }
15484
+ return r;
15089
15485
  }
15090
- setText(text) {
15091
- this.#completionEpoch++;
15092
- this.resetEscapeSequence();
15093
- super.setText(text);
15486
+ }
15487
+ html(e) {
15488
+ let t = this.rules.block.html.exec(e);
15489
+ if (t) {
15490
+ let n = ie(t[0]);
15491
+ return { type: "html", block: true, raw: n, pre: t[1] === "pre" || t[1] === "script" || t[1] === "style", text: n };
15094
15492
  }
15095
- handleInput(data) {
15096
- if (isKeyRelease(data))
15493
+ }
15494
+ def(e) {
15495
+ let t = this.rules.block.def.exec(e);
15496
+ if (t) {
15497
+ if (!this.rules.other.startAngleBracket.test(t[2]) && oe(t[2], "()") !== -1)
15097
15498
  return;
15098
- this.#completionEpoch++;
15099
- if (matchesKey3(data, "escape") && this.isShowingAutocomplete()) {
15100
- this.resetEscapeSequence();
15101
- super.handleInput(data);
15499
+ let n = q(t[1]).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];
15500
+ return { type: "def", tag: n, raw: L(t[0], `
15501
+ `), href: s, title: r };
15502
+ }
15503
+ }
15504
+ table(e) {
15505
+ let t = this.rules.block.table.exec(e);
15506
+ if (!t || !this.rules.other.tableDelimiter.test(t[2]))
15507
+ return;
15508
+ let n = se(t[1]), s = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), r = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(`
15509
+ `) : [], o = { type: "table", raw: L(t[0], `
15510
+ `), header: [], align: [], rows: [] };
15511
+ if (n.length === s.length) {
15512
+ for (let i of s)
15513
+ 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);
15514
+ for (let i = 0;i < n.length; i++)
15515
+ o.header.push({ text: n[i], tokens: this.lexer.inline(n[i]), header: true, align: o.align[i] });
15516
+ for (let i of r)
15517
+ o.rows.push(se(i, o.header.length).map((u, a) => ({ text: u, tokens: this.lexer.inline(u), header: false, align: o.align[a] })));
15518
+ return o;
15519
+ }
15520
+ }
15521
+ lheading(e) {
15522
+ let t = this.rules.block.lheading.exec(e);
15523
+ if (t) {
15524
+ let n = t[1].trim();
15525
+ return { type: "heading", raw: L(t[0], `
15526
+ `), depth: t[2].charAt(0) === "=" ? 1 : 2, text: n, tokens: this.lexer.inline(n) };
15527
+ }
15528
+ }
15529
+ paragraph(e) {
15530
+ let t = this.rules.block.paragraph.exec(e);
15531
+ if (t) {
15532
+ let n = t[1].charAt(t[1].length - 1) === `
15533
+ ` ? t[1].slice(0, -1) : t[1];
15534
+ return { type: "paragraph", raw: t[0], text: n, tokens: this.lexer.inline(n) };
15535
+ }
15536
+ }
15537
+ text(e) {
15538
+ let t = this.rules.block.text.exec(e);
15539
+ if (t)
15540
+ return { type: "text", raw: t[0], text: t[0], tokens: this.lexer.inline(t[0]) };
15541
+ }
15542
+ escape(e) {
15543
+ let t = this.rules.inline.escape.exec(e);
15544
+ if (t)
15545
+ return { type: "escape", raw: t[0], text: t[1] };
15546
+ }
15547
+ tag(e) {
15548
+ let t = this.rules.inline.tag.exec(e);
15549
+ if (t)
15550
+ 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] };
15551
+ }
15552
+ link(e) {
15553
+ if (this.lexer.state.linkParenPossible === false)
15554
+ return;
15555
+ let t = this.rules.inline.link.exec(e);
15556
+ if (t) {
15557
+ let n = t[0].charAt(0) === "!" ? 2 : 1;
15558
+ if (!this.options.pedantic && we(e, t[1], n, this.rules))
15102
15559
  return;
15103
- }
15104
- if (matchesKey3(data, "escape")) {
15105
- if (this.#completionProvider)
15106
- super.setAutocompleteProvider(this.#completionProvider);
15107
- if (isKeyRepeat(data))
15560
+ let s = t[2].trim();
15561
+ if (!this.options.pedantic && this.rules.other.startAngleBracket.test(s)) {
15562
+ if (!this.rules.other.endAngleBracket.test(s))
15108
15563
  return;
15109
- const now = Date.now();
15110
- if (this.#lastEscape && now - this.#lastEscape <= 400) {
15111
- this.#lastEscape = 0;
15112
- this.setText("");
15113
- this.onClearDraft?.();
15564
+ let i = L(s.slice(0, -1), "\\");
15565
+ if ((s.length - i.length) % 2 === 0)
15566
+ return;
15567
+ } else {
15568
+ let i = oe(t[2], "()");
15569
+ if (i === -2)
15114
15570
  return;
15571
+ if (i > -1) {
15572
+ let a = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + i;
15573
+ t[2] = t[2].substring(0, i), t[0] = t[0].substring(0, a).trim(), t[3] = "";
15115
15574
  }
15116
- this.#lastEscape = now;
15117
- super.handleInput(data);
15575
+ }
15576
+ let r = t[2], o = "";
15577
+ if (this.options.pedantic) {
15578
+ let i = this.rules.other.pedanticHrefTitle.exec(r);
15579
+ i && (r = i[1], o = i[3]);
15580
+ } else
15581
+ o = t[3] ? t[3].slice(1, -1) : "";
15582
+ return r = r.trim(), this.rules.other.startAngleBracket.test(r) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(s) ? r = r.slice(1) : r = r.slice(1, -1)), Oe(t, { href: r && r.replace(this.rules.inline.anyPunctuation, "$1"), title: o && o.replace(this.rules.inline.anyPunctuation, "$1") }, t[0], this.lexer, this.rules);
15583
+ }
15584
+ }
15585
+ reflink(e, t) {
15586
+ let n;
15587
+ if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
15588
+ let s = n[0].charAt(0) === "!" ? 2 : 1;
15589
+ if (!this.options.pedantic && we(e, n[1], s, this.rules))
15118
15590
  return;
15591
+ let r = (n[2] || n[1]).replace(this.rules.other.multipleSpaceGlobal, " "), o = t[q(r)];
15592
+ if (!o) {
15593
+ let i = n[0].charAt(0);
15594
+ return { type: "text", raw: i, text: i };
15119
15595
  }
15120
- this.#lastEscape = 0;
15596
+ return Oe(n, o, n[0], this.lexer, this.rules);
15597
+ }
15598
+ }
15599
+ emStrong(e, t, n = "") {
15600
+ let s = this.rules.inline.emStrongLDelim.exec(e);
15601
+ if (!s || !s[1] && !s[2] && !s[3] && !s[4] || s[4] && n.match(this.rules.other.unicodeAlphaNumeric))
15602
+ return;
15603
+ if (!(s[1] || s[3] || "") || !n || this.rules.inline.punctuation.exec(n)) {
15604
+ let o = [...s[0]].length - 1, i, u, a = o, p = 0, c = s[0][0], d = n === c, m = c === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
15605
+ for (m.lastIndex = 0, t = t.slice(-1 * e.length + o);(s = m.exec(t)) !== null; ) {
15606
+ if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i)
15607
+ continue;
15608
+ if (u = [...i].length, s[3] || s[4]) {
15609
+ a += u;
15610
+ continue;
15611
+ } else if (s[5] || s[6]) {
15612
+ if (o % 3 && !((o + u) % 3)) {
15613
+ p += u;
15614
+ continue;
15615
+ }
15616
+ if (d)
15617
+ break;
15618
+ }
15619
+ if (a -= u, a > 0)
15620
+ continue;
15621
+ u = Math.min(u, u + a + p);
15622
+ let b = [...s[0]][0].length, g = e.slice(0, o + s.index + b + u);
15623
+ if (Math.min(o, u) % 2) {
15624
+ let f = g.slice(1, -1);
15625
+ return { type: "em", raw: g, text: f, tokens: this.lexer.inlineTokens(f) };
15626
+ }
15627
+ let w = g.slice(2, -2);
15628
+ return { type: "strong", raw: g, text: w, tokens: this.lexer.inlineTokens(w) };
15629
+ }
15630
+ }
15631
+ }
15632
+ codespan(e) {
15633
+ let t = this.rules.inline.code.exec(e);
15634
+ if (t) {
15635
+ 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);
15636
+ return s && r && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t[0], text: n };
15637
+ }
15638
+ }
15639
+ br(e) {
15640
+ let t = this.rules.inline.br.exec(e);
15641
+ if (t)
15642
+ return { type: "br", raw: t[0] };
15643
+ }
15644
+ del(e, t, n = "") {
15645
+ let s = this.rules.inline.delLDelim.exec(e);
15646
+ if (!s)
15647
+ return;
15648
+ if (!(s[1] || "") || !n || this.rules.inline.punctuation.exec(n)) {
15649
+ let o = [...s[0]].length - 1, i, u, a = o, p = this.rules.inline.delRDelim;
15650
+ for (p.lastIndex = 0, t = t.slice(-1 * e.length + o);(s = p.exec(t)) !== null; ) {
15651
+ if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i || (u = [...i].length, u !== o))
15652
+ continue;
15653
+ if (s[3] || s[4]) {
15654
+ a += u;
15655
+ continue;
15656
+ }
15657
+ if (a -= u, a > 0)
15658
+ continue;
15659
+ u = Math.min(u, u + a);
15660
+ let c = [...s[0]][0].length, d = e.slice(0, o + s.index + c + u), m = d.slice(o, -o);
15661
+ return { type: "del", raw: d, text: m, tokens: this.lexer.inlineTokens(m) };
15662
+ }
15663
+ }
15664
+ }
15665
+ autolink(e) {
15666
+ let t = this.rules.inline.autolink.exec(e);
15667
+ if (t) {
15668
+ let n, s;
15669
+ 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 }] };
15670
+ }
15671
+ }
15672
+ url(e) {
15673
+ let t;
15674
+ if (t = this.rules.inline.url.exec(e)) {
15675
+ let n, s;
15676
+ if (t[2] === "@")
15677
+ n = t[0], s = "mailto:" + n;
15678
+ else {
15679
+ let r;
15680
+ do
15681
+ r = t[0], t[0] = this.rules.inline._backpedal.exec(t[0])?.[0] ?? "";
15682
+ while (r !== t[0]);
15683
+ n = t[0], t[1] === "www." ? s = "http://" + t[0] : s = t[0];
15684
+ }
15685
+ return { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
15686
+ }
15687
+ }
15688
+ inlineText(e) {
15689
+ let t = this.rules.inline.text.exec(e);
15690
+ if (t) {
15691
+ let n = this.lexer.state.inRawBlock;
15692
+ return { type: "text", raw: t[0], text: n ? t[0] : Te(t[0]), escaped: n };
15693
+ }
15694
+ }
15695
+ }, R = class l {
15696
+ tokens;
15697
+ options;
15698
+ state;
15699
+ inlineQueue;
15700
+ tokenizer;
15701
+ constructor(e) {
15702
+ this.tokens = [], this.tokens.links = Object.create(null), this.options = e || P, 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, linkParenPossible: true, top: true };
15703
+ let t = { other: x, block: j.normal, inline: D.normal };
15704
+ this.options.pedantic ? (t.block = j.pedantic, t.inline = D.pedantic) : this.options.gfm && (t.block = j.gfm, this.options.breaks ? t.inline = D.breaks : t.inline = D.gfm), this.tokenizer.rules = t;
15705
+ }
15706
+ static get rules() {
15707
+ return { block: j, inline: D };
15708
+ }
15709
+ static lex(e, t) {
15710
+ return new l(t).lex(e);
15711
+ }
15712
+ static lexInline(e, t) {
15713
+ return new l(t).inlineTokens(e);
15714
+ }
15715
+ lex(e) {
15716
+ e = e.replace(x.carriageReturn, `
15717
+ `), this.blockTokens(e, this.tokens);
15718
+ for (let t = 0;t < this.inlineQueue.length; t++) {
15719
+ let n = this.inlineQueue[t];
15720
+ this.inlineTokens(n.src, n.tokens);
15721
+ }
15722
+ return this.inlineQueue = [], this.tokens;
15723
+ }
15724
+ blockTokens(e, t = [], n = false) {
15725
+ this.tokenizer.lexer = this, this.options.pedantic && (e = e.replace(x.tabCharGlobal, " ").replace(x.spaceLine, ""));
15726
+ let s = 1 / 0;
15727
+ for (;e; ) {
15728
+ if (e.length < s)
15729
+ s = e.length;
15730
+ else {
15731
+ this.infiniteLoopError(e.charCodeAt(0));
15732
+ break;
15733
+ }
15734
+ let r;
15735
+ 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))
15736
+ continue;
15737
+ if (r = this.tokenizer.space(e)) {
15738
+ e = e.substring(r.raw.length);
15739
+ let i = t.at(-1);
15740
+ r.raw.length === 1 && i !== undefined ? i.raw += `
15741
+ ` : t.push(r);
15742
+ continue;
15743
+ }
15744
+ if (r = this.tokenizer.code(e)) {
15745
+ e = e.substring(r.raw.length);
15746
+ let i = t.at(-1);
15747
+ i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
15748
+ `) ? "" : `
15749
+ `) + r.raw, i.text += `
15750
+ ` + r.text, this.inlineQueue.at(-1).src = i.text) : t.push(r);
15751
+ continue;
15752
+ }
15753
+ if (r = this.tokenizer.fences(e)) {
15754
+ e = e.substring(r.raw.length), t.push(r);
15755
+ continue;
15756
+ }
15757
+ if (r = this.tokenizer.heading(e)) {
15758
+ e = e.substring(r.raw.length), t.push(r);
15759
+ continue;
15760
+ }
15761
+ if (r = this.tokenizer.hr(e)) {
15762
+ e = e.substring(r.raw.length), t.push(r);
15763
+ continue;
15764
+ }
15765
+ if (r = this.tokenizer.blockquote(e)) {
15766
+ e = e.substring(r.raw.length), t.push(r);
15767
+ continue;
15768
+ }
15769
+ if (r = this.tokenizer.list(e)) {
15770
+ e = e.substring(r.raw.length), t.push(r);
15771
+ continue;
15772
+ }
15773
+ if (r = this.tokenizer.html(e)) {
15774
+ e = e.substring(r.raw.length), t.push(r);
15775
+ continue;
15776
+ }
15777
+ if (r = this.tokenizer.def(e)) {
15778
+ e = e.substring(r.raw.length);
15779
+ let i = t.at(-1);
15780
+ i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
15781
+ `) ? "" : `
15782
+ `) + r.raw, i.text += `
15783
+ ` + 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));
15784
+ continue;
15785
+ }
15786
+ if (r = this.tokenizer.table(e)) {
15787
+ e = e.substring(r.raw.length), t.push(r);
15788
+ continue;
15789
+ }
15790
+ if (r = this.tokenizer.lheading(e)) {
15791
+ e = e.substring(r.raw.length), t.push(r);
15792
+ continue;
15793
+ }
15794
+ let o = e;
15795
+ if (this.options.extensions?.startBlock) {
15796
+ let i = 1 / 0, u = e.slice(1), a;
15797
+ this.options.extensions.startBlock.forEach((p) => {
15798
+ a = p.call({ lexer: this }, u), typeof a == "number" && a >= 0 && (i = Math.min(i, a));
15799
+ }), i < 1 / 0 && i >= 0 && (o = e.substring(0, i + 1));
15800
+ }
15801
+ if (this.state.top && (r = this.tokenizer.paragraph(o))) {
15802
+ let i = t.at(-1);
15803
+ n && i?.type === "paragraph" ? (i.raw += (i.raw.endsWith(`
15804
+ `) ? "" : `
15805
+ `) + r.raw, i.text += `
15806
+ ` + 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);
15807
+ continue;
15808
+ }
15809
+ if (r = this.tokenizer.text(e)) {
15810
+ e = e.substring(r.raw.length);
15811
+ let i = t.at(-1);
15812
+ i?.type === "text" ? (i.raw += (i.raw.endsWith(`
15813
+ `) ? "" : `
15814
+ `) + r.raw, i.text += `
15815
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r);
15816
+ continue;
15817
+ }
15818
+ if (e) {
15819
+ this.infiniteLoopError(e.charCodeAt(0));
15820
+ break;
15821
+ }
15822
+ }
15823
+ return this.state.top = true, t;
15824
+ }
15825
+ inline(e, t = []) {
15826
+ return this.inlineQueue.push({ src: e, tokens: t }), t;
15827
+ }
15828
+ linkInText(e) {
15829
+ if (!e.includes("["))
15830
+ return false;
15831
+ let t = this.tokenizer.rules.inline.link;
15832
+ for (let n of e.matchAll(this.tokenizer.rules.inline.blockSkip))
15833
+ if (t.test(n[0]) && e.charAt(n.index - 1) !== "!")
15834
+ return true;
15835
+ for (let n of e.matchAll(this.tokenizer.rules.inline.reflinkSearch)) {
15836
+ let s = n[0], r = s.lastIndexOf("[");
15837
+ if (!(s.charAt(0) === "!" || !Object.hasOwn(this.tokens.links, q(s.slice(r + 1, -1)))) && !(r > 1 && this.linkInText(s.slice(1, r - 1))))
15838
+ return true;
15839
+ }
15840
+ return false;
15841
+ }
15842
+ inlineTokens(e, t = []) {
15843
+ this.tokenizer.lexer = this;
15844
+ let n = this.state.linkParenPossible;
15845
+ this.state.linkParenPossible = n && e.includes(")");
15846
+ try {
15847
+ return this.#e(e, t);
15848
+ } finally {
15849
+ this.state.linkParenPossible = n;
15850
+ }
15851
+ }
15852
+ #e(e, t) {
15853
+ let n = e;
15854
+ if (this.tokens.links && e.includes("[")) {
15855
+ let i = this.tokenizer.rules.inline.reflinkSearch, u = (a) => {
15856
+ let p = a.lastIndexOf("[");
15857
+ if (!Object.hasOwn(this.tokens.links, q(a.slice(p + 1, -1))))
15858
+ return a;
15859
+ if (p > 1 && a.charAt(0) !== "!") {
15860
+ let c = a.slice(1, p - 1);
15861
+ if (this.linkInText(c))
15862
+ return "[" + c.replace(i, u) + "][" + "a".repeat(a.length - p - 2) + "]";
15863
+ }
15864
+ return "[" + "a".repeat(a.length - 2) + "]";
15865
+ };
15866
+ n = n.replace(i, u);
15867
+ }
15868
+ n = n.replace(this.tokenizer.rules.inline.anyPunctuation, (i) => "+".repeat(i.length)), n = n.replace(this.tokenizer.rules.inline.blockSkip, (i, u, a) => {
15869
+ let p = a ? a.length : 0;
15870
+ return i.slice(0, p) + "[" + "a".repeat(i.length - p - 2) + "]";
15871
+ }), n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n;
15872
+ let s = false, r = "", o = 1 / 0;
15873
+ for (;e; ) {
15874
+ if (e.length < o)
15875
+ o = e.length;
15876
+ else {
15877
+ this.infiniteLoopError(e.charCodeAt(0));
15878
+ break;
15879
+ }
15880
+ s || (r = ""), s = false;
15881
+ let i;
15882
+ 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))
15883
+ continue;
15884
+ if (i = this.tokenizer.escape(e)) {
15885
+ e = e.substring(i.raw.length), t.push(i);
15886
+ continue;
15887
+ }
15888
+ if (i = this.tokenizer.tag(e)) {
15889
+ e = e.substring(i.raw.length), t.push(i);
15890
+ continue;
15891
+ }
15892
+ if (i = this.tokenizer.link(e)) {
15893
+ e = e.substring(i.raw.length), t.push(i);
15894
+ continue;
15895
+ }
15896
+ if (i = this.tokenizer.reflink(e, this.tokens.links)) {
15897
+ e = e.substring(i.raw.length);
15898
+ let a = t.at(-1);
15899
+ i.type === "text" && a?.type === "text" ? (a.raw += i.raw, a.text += i.text) : t.push(i);
15900
+ continue;
15901
+ }
15902
+ if (i = this.tokenizer.emStrong(e, n, r)) {
15903
+ e = e.substring(i.raw.length), t.push(i);
15904
+ continue;
15905
+ }
15906
+ if (i = this.tokenizer.codespan(e)) {
15907
+ e = e.substring(i.raw.length), t.push(i);
15908
+ continue;
15909
+ }
15910
+ if (i = this.tokenizer.br(e)) {
15911
+ e = e.substring(i.raw.length), t.push(i);
15912
+ continue;
15913
+ }
15914
+ if (i = this.tokenizer.del(e, n, r)) {
15915
+ e = e.substring(i.raw.length), t.push(i);
15916
+ continue;
15917
+ }
15918
+ if (i = this.tokenizer.autolink(e)) {
15919
+ e = e.substring(i.raw.length), t.push(i);
15920
+ continue;
15921
+ }
15922
+ if (!this.state.inLink && (i = this.tokenizer.url(e))) {
15923
+ e = e.substring(i.raw.length), t.push(i);
15924
+ continue;
15925
+ }
15926
+ let u = e;
15927
+ if (this.options.extensions?.startInline) {
15928
+ let a = 1 / 0, p = e.slice(1), c;
15929
+ this.options.extensions.startInline.forEach((d) => {
15930
+ c = d.call({ lexer: this }, p), typeof c == "number" && c >= 0 && (a = Math.min(a, c));
15931
+ }), a < 1 / 0 && a >= 0 && (u = e.substring(0, a + 1));
15932
+ }
15933
+ if (i = this.tokenizer.inlineText(u)) {
15934
+ e = e.substring(i.raw.length), i.raw.slice(-1) !== "_" && (r = i.raw.slice(-1)), s = true;
15935
+ let a = t.at(-1);
15936
+ a?.type === "text" ? (a.raw += i.raw, a.text += i.text) : t.push(i);
15937
+ continue;
15938
+ }
15939
+ if (e) {
15940
+ this.infiniteLoopError(e.charCodeAt(0));
15941
+ break;
15942
+ }
15943
+ }
15944
+ return t;
15945
+ }
15946
+ infiniteLoopError(e) {
15947
+ let t = "Infinite loop on byte: " + e;
15948
+ if (this.options.silent)
15949
+ console.error(t);
15950
+ else
15951
+ throw new Error(t);
15952
+ }
15953
+ }, S = class {
15954
+ options;
15955
+ parser;
15956
+ constructor(e) {
15957
+ this.options = e || P;
15958
+ }
15959
+ space(e) {
15960
+ return "";
15961
+ }
15962
+ code({ text: e, lang: t, escaped: n }) {
15963
+ let s = (t || "").match(x.notSpaceStart)?.[0], r = e ? e.replace(x.endingNewline, "") + `
15964
+ ` : "";
15965
+ return s ? '<pre><code class="language-' + O(s) + '">' + (n ? r : O(r, true)) + `</code></pre>
15966
+ ` : "<pre><code>" + (n ? r : O(r, true)) + `</code></pre>
15967
+ `;
15968
+ }
15969
+ blockquote({ tokens: e }) {
15970
+ return `<blockquote>
15971
+ ${this.parser.parse(e)}</blockquote>
15972
+ `;
15973
+ }
15974
+ html({ text: e }) {
15975
+ return e;
15976
+ }
15977
+ def(e) {
15978
+ return "";
15979
+ }
15980
+ heading({ tokens: e, depth: t }) {
15981
+ return `<h${t}>${this.parser.parseInline(e)}</h${t}>
15982
+ `;
15983
+ }
15984
+ hr(e) {
15985
+ return `<hr>
15986
+ `;
15987
+ }
15988
+ list(e) {
15989
+ let { ordered: t, start: n } = e, s = "";
15990
+ for (let i = 0;i < e.items.length; i++) {
15991
+ let u = e.items[i];
15992
+ s += this.listitem(u);
15993
+ }
15994
+ let r = t ? "ol" : "ul", o = t && n !== 1 ? ' start="' + n + '"' : "";
15995
+ return "<" + r + o + `>
15996
+ ` + s + "</" + r + `>
15997
+ `;
15998
+ }
15999
+ listitem(e) {
16000
+ return `<li>${this.parser.parse(e.tokens)}</li>
16001
+ `;
16002
+ }
16003
+ checkbox({ checked: e }) {
16004
+ return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox"> ';
16005
+ }
16006
+ paragraph({ tokens: e }) {
16007
+ return `<p>${this.parser.parseInline(e)}</p>
16008
+ `;
16009
+ }
16010
+ table(e) {
16011
+ let t = "", n = "";
16012
+ for (let r = 0;r < e.header.length; r++)
16013
+ n += this.tablecell(e.header[r]);
16014
+ t += this.tablerow({ text: n });
16015
+ let s = "";
16016
+ for (let r = 0;r < e.rows.length; r++) {
16017
+ let o = e.rows[r];
16018
+ n = "";
16019
+ for (let i = 0;i < o.length; i++)
16020
+ n += this.tablecell(o[i]);
16021
+ s += this.tablerow({ text: n });
16022
+ }
16023
+ return s && (s = `<tbody>${s}</tbody>`), `<table>
16024
+ <thead>
16025
+ ` + t + `</thead>
16026
+ ` + s + `</table>
16027
+ `;
16028
+ }
16029
+ tablerow({ text: e }) {
16030
+ return `<tr>
16031
+ ${e}</tr>
16032
+ `;
16033
+ }
16034
+ tablecell(e) {
16035
+ let t = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
16036
+ return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t + `</${n}>
16037
+ `;
16038
+ }
16039
+ strong({ tokens: e }) {
16040
+ return `<strong>${this.parser.parseInline(e)}</strong>`;
16041
+ }
16042
+ em({ tokens: e }) {
16043
+ return `<em>${this.parser.parseInline(e)}</em>`;
16044
+ }
16045
+ codespan({ text: e }) {
16046
+ return `<code>${O(e, true)}</code>`;
16047
+ }
16048
+ br(e) {
16049
+ return "<br>";
16050
+ }
16051
+ del({ tokens: e }) {
16052
+ return `<del>${this.parser.parseInline(e)}</del>`;
16053
+ }
16054
+ link({ href: e, title: t, text: n, tokens: s, autolink: r }) {
16055
+ let o = r ? O(n, true) : this.parser.parseInline(s), i = re(e);
16056
+ if (i === null)
16057
+ return o;
16058
+ e = O(i, r);
16059
+ let u = '<a href="' + e + '"';
16060
+ return t && (u += ' title="' + O(t) + '"'), u += ">" + o + "</a>", u;
16061
+ }
16062
+ image({ href: e, title: t, text: n, tokens: s }) {
16063
+ s && (n = this.parser.parseInline(s, this.parser.textRenderer));
16064
+ let r = re(e);
16065
+ if (r === null)
16066
+ return O(n);
16067
+ e = r;
16068
+ let o = `<img src="${O(e)}" alt="${O(n)}"`;
16069
+ return t && (o += ` title="${O(t)}"`), o += ">", o;
16070
+ }
16071
+ text(e) {
16072
+ return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : ("escaped" in e) && e.escaped ? e.text : O(e.text);
16073
+ }
16074
+ }, z = class {
16075
+ strong({ text: e }) {
16076
+ return e;
16077
+ }
16078
+ em({ text: e }) {
16079
+ return e;
16080
+ }
16081
+ codespan({ text: e }) {
16082
+ return e;
16083
+ }
16084
+ del({ text: e }) {
16085
+ return e;
16086
+ }
16087
+ html({ text: e }) {
16088
+ return e;
16089
+ }
16090
+ text({ text: e }) {
16091
+ return e;
16092
+ }
16093
+ link({ text: e }) {
16094
+ return "" + e;
16095
+ }
16096
+ image({ text: e }) {
16097
+ return "" + e;
16098
+ }
16099
+ br() {
16100
+ return "";
16101
+ }
16102
+ checkbox({ raw: e }) {
16103
+ return e;
16104
+ }
16105
+ }, T = class l {
16106
+ options;
16107
+ renderer;
16108
+ textRenderer;
16109
+ constructor(e) {
16110
+ this.options = e || P, this.options.renderer = this.options.renderer || new S, this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new z;
16111
+ }
16112
+ static parse(e, t) {
16113
+ return new l(t).parse(e);
16114
+ }
16115
+ static parseInline(e, t) {
16116
+ return new l(t).parseInline(e);
16117
+ }
16118
+ parse(e) {
16119
+ this.renderer.parser = this;
16120
+ let t = "";
16121
+ for (let n = 0;n < e.length; n++) {
16122
+ let s = e[n];
16123
+ if (this.options.extensions?.renderers?.[s.type]) {
16124
+ let o = s, i = this.options.extensions.renderers[o.type].call({ parser: this }, o);
16125
+ if (i !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "checkbox", "html", "def", "paragraph", "text"].includes(o.type)) {
16126
+ t += i || "";
16127
+ continue;
16128
+ }
16129
+ }
16130
+ let r = s;
16131
+ switch (r.type) {
16132
+ case "space": {
16133
+ t += this.renderer.space(r);
16134
+ break;
16135
+ }
16136
+ case "hr": {
16137
+ t += this.renderer.hr(r);
16138
+ break;
16139
+ }
16140
+ case "heading": {
16141
+ t += this.renderer.heading(r);
16142
+ break;
16143
+ }
16144
+ case "code": {
16145
+ t += this.renderer.code(r);
16146
+ break;
16147
+ }
16148
+ case "table": {
16149
+ t += this.renderer.table(r);
16150
+ break;
16151
+ }
16152
+ case "blockquote": {
16153
+ t += this.renderer.blockquote(r);
16154
+ break;
16155
+ }
16156
+ case "list": {
16157
+ t += this.renderer.list(r);
16158
+ break;
16159
+ }
16160
+ case "checkbox": {
16161
+ t += this.renderer.checkbox(r);
16162
+ break;
16163
+ }
16164
+ case "html": {
16165
+ t += this.renderer.html(r);
16166
+ break;
16167
+ }
16168
+ case "def": {
16169
+ t += this.renderer.def(r);
16170
+ break;
16171
+ }
16172
+ case "paragraph": {
16173
+ t += this.renderer.paragraph(r);
16174
+ break;
16175
+ }
16176
+ case "text": {
16177
+ t += this.renderer.text(r);
16178
+ break;
16179
+ }
16180
+ default: {
16181
+ let o = 'Token with "' + r.type + '" type was not found.';
16182
+ if (this.options.silent)
16183
+ return console.error(o), "";
16184
+ throw new Error(o);
16185
+ }
16186
+ }
16187
+ }
16188
+ return t;
16189
+ }
16190
+ parseInline(e, t = this.renderer) {
16191
+ this.renderer.parser = this;
16192
+ let n = "";
16193
+ for (let s = 0;s < e.length; s++) {
16194
+ let r = e[s];
16195
+ if (this.options.extensions?.renderers?.[r.type]) {
16196
+ let i = this.options.extensions.renderers[r.type].call({ parser: this }, r);
16197
+ if (i !== false || !["escape", "html", "link", "image", "checkbox", "strong", "em", "codespan", "br", "del", "text"].includes(r.type)) {
16198
+ n += i || "";
16199
+ continue;
16200
+ }
16201
+ }
16202
+ let o = r;
16203
+ switch (o.type) {
16204
+ case "escape": {
16205
+ n += t.text(o);
16206
+ break;
16207
+ }
16208
+ case "html": {
16209
+ n += t.html(o);
16210
+ break;
16211
+ }
16212
+ case "link": {
16213
+ n += t.link(o);
16214
+ break;
16215
+ }
16216
+ case "image": {
16217
+ n += t.image(o);
16218
+ break;
16219
+ }
16220
+ case "checkbox": {
16221
+ n += t.checkbox(o);
16222
+ break;
16223
+ }
16224
+ case "strong": {
16225
+ n += t.strong(o);
16226
+ break;
16227
+ }
16228
+ case "em": {
16229
+ n += t.em(o);
16230
+ break;
16231
+ }
16232
+ case "codespan": {
16233
+ n += t.codespan(o);
16234
+ break;
16235
+ }
16236
+ case "br": {
16237
+ n += t.br(o);
16238
+ break;
16239
+ }
16240
+ case "del": {
16241
+ n += t.del(o);
16242
+ break;
16243
+ }
16244
+ case "text": {
16245
+ n += t.text(o);
16246
+ break;
16247
+ }
16248
+ default: {
16249
+ let i = 'Token with "' + o.type + '" type was not found.';
16250
+ if (this.options.silent)
16251
+ return console.error(i), "";
16252
+ throw new Error(i);
16253
+ }
16254
+ }
16255
+ }
16256
+ return n;
16257
+ }
16258
+ }, _, F = class {
16259
+ defaults = I();
16260
+ options = this.setOptions;
16261
+ parse = this.parseMarkdown(true);
16262
+ parseInline = this.parseMarkdown(false);
16263
+ Parser = T;
16264
+ Renderer = S;
16265
+ TextRenderer = z;
16266
+ Lexer = R;
16267
+ Tokenizer = y;
16268
+ Hooks = _;
16269
+ constructor(...e) {
16270
+ this.use(...e);
16271
+ }
16272
+ walkTokens(e, t) {
16273
+ let n = [];
16274
+ for (let s of e)
16275
+ switch (n = n.concat(t.call(this, s)), s.type) {
16276
+ case "table": {
16277
+ let r = s;
16278
+ for (let o of r.header)
16279
+ n = n.concat(this.walkTokens(o.tokens, t));
16280
+ for (let o of r.rows)
16281
+ for (let i of o)
16282
+ n = n.concat(this.walkTokens(i.tokens, t));
16283
+ break;
16284
+ }
16285
+ case "list": {
16286
+ let r = s;
16287
+ n = n.concat(this.walkTokens(r.items, t));
16288
+ break;
16289
+ }
16290
+ default: {
16291
+ let r = s;
16292
+ this.defaults.extensions?.childTokens?.[r.type] ? this.defaults.extensions.childTokens[r.type].forEach((o) => {
16293
+ let i = r[o].flat(1 / 0);
16294
+ n = n.concat(this.walkTokens(i, t));
16295
+ }) : r.tokens && (n = n.concat(this.walkTokens(r.tokens, t)));
16296
+ }
16297
+ }
16298
+ return n;
16299
+ }
16300
+ use(...e) {
16301
+ let t = this.defaults.extensions || { renderers: {}, childTokens: {} };
16302
+ return e.forEach((n) => {
16303
+ let s = { ...n };
16304
+ if (s.async = this.defaults.async || s.async || false, n.extensions && (n.extensions.forEach((r) => {
16305
+ if (!r.name)
16306
+ throw new Error("extension name required");
16307
+ if ("renderer" in r) {
16308
+ let o = t.renderers[r.name];
16309
+ o ? t.renderers[r.name] = function(...i) {
16310
+ let u = r.renderer.apply(this, i);
16311
+ return u === false && (u = o.apply(this, i)), u;
16312
+ } : t.renderers[r.name] = r.renderer;
16313
+ }
16314
+ if ("tokenizer" in r) {
16315
+ if (!r.level || r.level !== "block" && r.level !== "inline")
16316
+ throw new Error("extension level must be 'block' or 'inline'");
16317
+ let o = t[r.level];
16318
+ 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]));
16319
+ }
16320
+ "childTokens" in r && r.childTokens && (t.childTokens[r.name] = r.childTokens);
16321
+ }), s.extensions = t), n.renderer) {
16322
+ let r = this.defaults.renderer || new S(this.defaults);
16323
+ for (let o in n.renderer) {
16324
+ if (!(o in r))
16325
+ throw new Error(`renderer '${o}' does not exist`);
16326
+ if (["options", "parser"].includes(o))
16327
+ continue;
16328
+ let i = o, u = n.renderer[i], a = r[i];
16329
+ r[i] = (...p) => {
16330
+ let c = u.apply(r, p);
16331
+ return c === false && (c = a.apply(r, p)), c || "";
16332
+ };
16333
+ }
16334
+ s.renderer = r;
16335
+ }
16336
+ if (n.tokenizer) {
16337
+ let r = this.defaults.tokenizer || new y(this.defaults);
16338
+ for (let o in n.tokenizer) {
16339
+ if (!(o in r))
16340
+ throw new Error(`tokenizer '${o}' does not exist`);
16341
+ if (["options", "rules", "lexer"].includes(o))
16342
+ continue;
16343
+ let i = o, u = n.tokenizer[i], a = r[i];
16344
+ r[i] = (...p) => {
16345
+ let c = u.apply(r, p);
16346
+ return c === false && (c = a.apply(r, p)), c;
16347
+ };
16348
+ }
16349
+ s.tokenizer = r;
16350
+ }
16351
+ if (n.hooks) {
16352
+ let r = this.defaults.hooks || new _;
16353
+ for (let o in n.hooks) {
16354
+ if (!(o in r))
16355
+ throw new Error(`hook '${o}' does not exist`);
16356
+ if (["options", "block"].includes(o))
16357
+ continue;
16358
+ let i = o, u = n.hooks[i], a = r[i];
16359
+ _.passThroughHooks.has(o) ? r[i] = (p) => {
16360
+ if (this.defaults.async && _.passThroughHooksRespectAsync.has(o))
16361
+ return (async () => {
16362
+ let d = await u.call(r, p);
16363
+ return a.call(r, d);
16364
+ })();
16365
+ let c = u.call(r, p);
16366
+ return a.call(r, c);
16367
+ } : r[i] = (...p) => {
16368
+ if (this.defaults.async)
16369
+ return (async () => {
16370
+ let d = await u.apply(r, p);
16371
+ return d === false && (d = await a.apply(r, p)), d;
16372
+ })();
16373
+ let c = u.apply(r, p);
16374
+ return c === false && (c = a.apply(r, p)), c;
16375
+ };
16376
+ }
16377
+ s.hooks = r;
16378
+ }
16379
+ if (n.walkTokens) {
16380
+ let r = this.defaults.walkTokens, o = n.walkTokens;
16381
+ s.walkTokens = function(i) {
16382
+ let u = [];
16383
+ return u.push(o.call(this, i)), r && (u = u.concat(r.call(this, i))), u;
16384
+ };
16385
+ }
16386
+ this.defaults = { ...this.defaults, ...s };
16387
+ }), this;
16388
+ }
16389
+ setOptions(e) {
16390
+ return this.defaults = { ...this.defaults, ...e }, this;
16391
+ }
16392
+ lexer(e, t) {
16393
+ return R.lex(e, t ?? this.defaults);
16394
+ }
16395
+ parser(e, t) {
16396
+ return T.parse(e, t ?? this.defaults);
16397
+ }
16398
+ parseMarkdown(e) {
16399
+ return (n, s) => {
16400
+ let r = { ...s }, o = { ...this.defaults, ...r }, i = this.onError(!!o.silent, !!o.async);
16401
+ if (this.defaults.async === true && r.async === false)
16402
+ 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."));
16403
+ if (typeof n > "u" || n === null)
16404
+ return i(new Error("marked(): input parameter is undefined or null"));
16405
+ if (typeof n != "string")
16406
+ return i(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
16407
+ if (o.hooks && (o.hooks.options = o, o.hooks.block = e), o.async)
16408
+ return (async () => {
16409
+ let u = o.hooks ? await o.hooks.preprocess(n) : n, p = await (o.hooks ? await o.hooks.provideLexer(e) : e ? R.lex : R.lexInline)(u, o), c = o.hooks ? await o.hooks.processAllTokens(p) : p;
16410
+ o.walkTokens && await Promise.all(this.walkTokens(c, o.walkTokens));
16411
+ let m = await (o.hooks ? await o.hooks.provideParser(e) : e ? T.parse : T.parseInline)(c, o);
16412
+ return o.hooks ? await o.hooks.postprocess(m) : m;
16413
+ })().catch(i);
16414
+ try {
16415
+ o.hooks && (n = o.hooks.preprocess(n));
16416
+ let a = (o.hooks ? o.hooks.provideLexer(e) : e ? R.lex : R.lexInline)(n, o);
16417
+ o.hooks && (a = o.hooks.processAllTokens(a)), o.walkTokens && this.walkTokens(a, o.walkTokens);
16418
+ let c = (o.hooks ? o.hooks.provideParser(e) : e ? T.parse : T.parseInline)(a, o);
16419
+ return o.hooks && (c = o.hooks.postprocess(c)), c;
16420
+ } catch (u) {
16421
+ return i(u);
16422
+ }
16423
+ };
16424
+ }
16425
+ onError(e, t) {
16426
+ return (n) => {
16427
+ if (n.message += `
16428
+ Please report this to https://github.com/markedjs/marked.`, e) {
16429
+ let s = "<p>An error occurred:</p><pre>" + O(n.message + "", true) + "</pre>";
16430
+ return t ? Promise.resolve(s) : s;
16431
+ }
16432
+ if (t)
16433
+ return Promise.reject(n);
16434
+ throw n;
16435
+ };
16436
+ }
16437
+ }, E, gn, fn, mn, xn, Rn, Tn;
16438
+ var init_marked_esm = __esm(() => {
16439
+ P = I();
16440
+ A = { exec: () => null };
16441
+ _e = ((l = "") => {
16442
+ try {
16443
+ return !!new RegExp("(?<=1)(?<!1)" + l);
16444
+ } catch {
16445
+ return false;
16446
+ }
16447
+ })();
16448
+ x = { codeRemoveIndent: /^(?: {0,3}\t| {1,4})/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, endingSpaceTabChar: /[ \t]$/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, leadingSpaceTab: /^[ \t]+/, 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, numericCharacterReference: /&#(?:(\d{1,7})|[Xx]([A-Fa-f0-9]{1,6}));/g, 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: (l) => new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: C((l) => new RegExp(`^ {0,${l}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)), hrRegex: C((l) => new RegExp(`^ {0,${l}}((?:-[ ]*){3,}|(?:_[ ]*){3,}|(?:\\*[ ]*){3,})(?:\\n+|$)`)), fencesBeginRegex: C((l) => new RegExp(`^ {0,${l}}(?:\`\`\`|~~~)`)), headingBeginRegex: C((l) => new RegExp(`^ {0,${l}}#`)), htmlBeginRegex: C((l) => new RegExp(`^ {0,${l}}(?:</?(?:${N})(?: +|$|/?>)|<(?:script|pre|style|textarea|!--))`, "i")), blockquoteBeginRegex: C((l) => new RegExp(`^ {0,${l}}>`)) };
16449
+ $e = /^(?:[ \t]*(?:\n|$))+/;
16450
+ Le = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
16451
+ ze = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
16452
+ G = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
16453
+ Ae = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
16454
+ J = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
16455
+ he = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |fences|blockquote|heading|hr|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/;
16456
+ de = h(he).replace(/bull/g, J).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(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
16457
+ Ee = h(he).replace(/bull/g, J).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(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
16458
+ V = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/;
16459
+ Me = /^[^\n]+/;
16460
+ Y = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/;
16461
+ Ie = h(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", Y).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
16462
+ Ce = h(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, J).getRegex();
16463
+ ee = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
16464
+ Be = h("^ {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[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][a-z0-9-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][a-z0-9-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))", "i").replace("comment", ee).replace("tag", N).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
16465
+ De = ke(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/);
16466
+ qe = ke(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/);
16467
+ ve = h(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", qe).getRegex();
16468
+ te = { blockquote: ve, code: Le, def: Ie, fences: ze, heading: Ae, hr: G, html: Be, lheading: de, list: Ce, newline: $e, paragraph: De, table: A, text: Me };
16469
+ ue = h("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", G).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3}\t)[^\\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", N).getRegex();
16470
+ Ze = { ...te, lheading: Ee, table: ue, paragraph: h(V).replace("hr", G).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", ue).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", N).getRegex() };
16471
+ He = { ...te, html: h(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", ee).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: A, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: h(V).replace("hr", G).replace("heading", ` *#{1,6} *[^
16472
+ ]`).replace("lheading", de).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
16473
+ Ge = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
16474
+ Ne = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
16475
+ ge = /^( {2,}|\\)\n(?!\s*$)[ \t]*/;
16476
+ Qe = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
16477
+ $ = /[\p{P}\p{S}]/u;
16478
+ B = /[\s\p{P}\p{S}]/u;
16479
+ Q = /[^\s\p{P}\p{S}]/u;
16480
+ je = h(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, B).getRegex();
16481
+ Fe = /[\p{Pi}\p{Ps}"']/u;
16482
+ fe = /(?!~)[\p{P}\p{S}]/u;
16483
+ Ue = /(?!~)[\s\p{P}\p{S}]/u;
16484
+ Ke = /(?:[^\s\p{P}\p{S}]|~)/u;
16485
+ We = h(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", _e ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
16486
+ me = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
16487
+ Xe = h(me, "u").replace(/punct/g, $).getRegex();
16488
+ Je = h(me, "u").replace(/punct/g, fe).getRegex();
16489
+ Ve = /^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/;
16490
+ Ye = h(Ve, "u").replace(/openQuote/g, Fe).replace(/punct/g, $).getRegex();
16491
+ et = h(xe, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
16492
+ tt = h(xe, "gu").replace(/notPunctSpace/g, Ke).replace(/punctSpace/g, Ue).replace(/punct/g, fe).getRegex();
16493
+ rt = h(nt, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
16494
+ st = h("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
16495
+ ot = h(it, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
16496
+ at = h(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, $).getRegex();
16497
+ ut = h(lt, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
16498
+ pt = h(/\\(punct)/, "gu").replace(/punct/g, $).getRegex();
16499
+ ct = h(/^<(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();
16500
+ ht = h(ee).replace("(?:-->|$)", "-->").getRegex();
16501
+ dt = h("^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", ht).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
16502
+ be = /\[(?:\\[\s\S]|[^\[\]\\])*\]/;
16503
+ U = h(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace("brackets", be).getRegex();
16504
+ kt = h(/^!?\[(label)\]\([ \t\n]*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?[ \t\n]*\)/).replace("label", U).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
16505
+ gt = h(/^!?\[(label)\]\[(ref)\]/).replace("label", U).replace("ref", Y).getRegex();
16506
+ ft = h(/^!?\[(ref)\](?:\[\])?/).replace("ref", Y).getRegex();
16507
+ pe = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\]){1,999}/;
16508
+ mt = h(/(?:[^\[\]\\`]*(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\]))){0,999}?[^\[\]\\`]*?/).replace("brackets", be).getRegex();
16509
+ xt = h("reflink|nolink(?!\\()", "g").replace("reflink", h(/^!?\[(label)\]\[(ref)\]/).replace("label", mt).replace("ref", pe).getRegex()).replace("nolink", h(/^!?\[(ref)\](?:\[\])?/).replace("ref", pe).getRegex()).getRegex();
16510
+ ce = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
16511
+ bt = /[A-Za-z0-9._+-]+@[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/;
16512
+ Rt = h(/(?:mailto:email|xmpp:email(?:\/[A-Za-z0-9@.]+)?)/).replace(/email/g, bt).getRegex();
16513
+ ne = { _backpedal: A, anyPunctuation: pt, autolink: ct, blockSkip: We, br: ge, code: Ne, del: A, delLDelim: A, delRDelim: A, emStrongLDelim: Xe, emStrongRDelimAst: et, emStrongRDelimUnd: st, escape: Ge, link: kt, nolink: ft, punctuation: je, reflink: gt, reflinkSearch: xt, tag: dt, text: Qe, url: A };
16514
+ Tt = { ...ne, emStrongLDelim: Ye, emStrongRDelimAst: rt, emStrongRDelimUnd: ot, link: h(/^!?\[(label)\]\((.*?)\)/).replace("label", U).getRegex(), reflink: h(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", U).getRegex() };
16515
+ X = { ...ne, emStrongRDelimAst: tt, emStrongLDelim: Je, delLDelim: at, delRDelim: ut, url: h(/^emailProtocol|^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("emailProtocol", Rt).replace("protocol", ce).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: h(/^(?:[^a-zA-Z0-9](?=emailProtocol)|(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9](?=emailProtocol)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))))/).replace("protocol", ce).replace(/emailProtocol/g, /(?:mailto|xmpp):/).getRegex() };
16516
+ Ot = { ...X, br: h(ge).replace("{2,}", "*").getRegex(), text: h(X.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
16517
+ j = { normal: te, gfm: Ze, pedantic: He };
16518
+ D = { normal: ne, gfm: X, breaks: Ot, pedantic: Tt };
16519
+ wt = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
16520
+ _ = class {
16521
+ options;
16522
+ block;
16523
+ constructor(e) {
16524
+ this.options = e || P;
16525
+ }
16526
+ static passThroughHooks = new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
16527
+ static passThroughHooksRespectAsync = new Set(["preprocess", "postprocess", "processAllTokens"]);
16528
+ preprocess(e) {
16529
+ return e;
16530
+ }
16531
+ postprocess(e) {
16532
+ return e;
16533
+ }
16534
+ processAllTokens(e) {
16535
+ return e;
16536
+ }
16537
+ emStrongMask(e) {
16538
+ return e;
16539
+ }
16540
+ provideLexer(e = this.block) {
16541
+ return e ? R.lex : R.lexInline;
16542
+ }
16543
+ provideParser(e = this.block) {
16544
+ return e ? T.parse : T.parseInline;
16545
+ }
16546
+ };
16547
+ E = new F;
16548
+ k.options = k.setOptions = function(l) {
16549
+ return E.setOptions(l), k.defaults = E.defaults, W(k.defaults), k;
16550
+ };
16551
+ k.getDefaults = I;
16552
+ k.defaults = P;
16553
+ k.use = yt;
16554
+ k.walkTokens = function(l, e) {
16555
+ return E.walkTokens(l, e);
16556
+ };
16557
+ k.parseInline = E.parseInline;
16558
+ k.Parser = T;
16559
+ k.parser = T.parse;
16560
+ k.Renderer = S;
16561
+ k.TextRenderer = z;
16562
+ k.Lexer = R;
16563
+ k.lexer = R.lex;
16564
+ k.Tokenizer = y;
16565
+ k.Hooks = _;
16566
+ k.parse = k;
16567
+ gn = k.options;
16568
+ fn = k.setOptions;
16569
+ mn = k.walkTokens;
16570
+ xn = k.parseInline;
16571
+ Rn = T.parse;
16572
+ Tn = R.lex;
16573
+ });
16574
+
16575
+ // packages/core/src/conversation-export-html.ts
16576
+ async function embedImages(items, loadImage) {
16577
+ const embedded = new Map;
16578
+ let used = 0;
16579
+ let skipped = 0;
16580
+ for (const item of items) {
16581
+ if (item.type !== "user" && item.type !== "tool")
16582
+ continue;
16583
+ for (const image of item.images ?? []) {
16584
+ let reason = null;
16585
+ if (loadImage === undefined)
16586
+ reason = "not embedded";
16587
+ else if (used + image.bytes > MAX_EMBEDDED_IMAGE_BYTES)
16588
+ reason = "over the embedding size limit";
16589
+ else {
16590
+ try {
16591
+ const file = await loadImage(image);
16592
+ if (!SAFE_IMAGE_TYPE.test(file.mimeType))
16593
+ reason = "unsupported image type";
16594
+ else if (used + file.bytes.length > MAX_EMBEDDED_IMAGE_BYTES)
16595
+ reason = "over the embedding size limit";
16596
+ else {
16597
+ used += file.bytes.length;
16598
+ const parts = [];
16599
+ for (let at = 0;at < file.bytes.length; at += BASE64_SLICE_BYTES)
16600
+ parts.push(encodeChunk(file.bytes.subarray(at, at + BASE64_SLICE_BYTES)));
16601
+ embedded.set(`${image.entryId}:${image.contentIndex}`, {
16602
+ src: `data:${file.mimeType.toLowerCase()};base64,${parts.join("")}`
16603
+ });
16604
+ }
16605
+ } catch {
16606
+ reason = "image unavailable";
16607
+ }
16608
+ }
16609
+ if (reason !== null) {
16610
+ embedded.set(`${image.entryId}:${image.contentIndex}`, { reason });
16611
+ skipped++;
16612
+ }
16613
+ }
16614
+ }
16615
+ return { embedded, skipped };
16616
+ }
16617
+ function renderImages(images, embedded) {
16618
+ return (images ?? []).map((image) => {
16619
+ const found = embedded.get(`${image.entryId}:${image.contentIndex}`);
16620
+ const label = escapeHtml(imageLabel(image));
16621
+ if (found !== undefined && "src" in found)
16622
+ return `<figure><img src="${found.src}" alt="${escapeHtml(image.name)}"><figcaption>${label}</figcaption></figure>`;
16623
+ const reason = found !== undefined && "reason" in found ? ` \u2014 ${found.reason}` : "";
16624
+ return `<p class="placeholder">[image: ${label}${reason}]</p>`;
16625
+ }).join("");
16626
+ }
16627
+ async function exportHtml(source, options) {
16628
+ const { embedded, skipped } = await embedImages(source.items, options.loadImage);
16629
+ const title = escapeHtml(oneLine(source.title) || FALLBACK_EXPORT_TITLE);
16630
+ const body = [];
16631
+ for (const item of source.items) {
16632
+ if (item.type === "system") {
16633
+ body.push(`<div class="system">${escapeHtml(oneLine(item.text))}</div>`);
16634
+ } else if (item.type === "user") {
16635
+ const text = userText2(item);
16636
+ body.push(`<section class="msg user"><div class="role">User</div>${text === "" ? "" : `<div class="text">${escapeHtml(text)}</div>`}${renderImages(item.images, embedded)}</section>`);
16637
+ } else if (item.type === "assistant") {
16638
+ const thinking = options.includeThinking && item.thinking.trim() !== "" ? `<details class="thinking"><summary>Thinking</summary><div class="text">${escapeHtml(item.thinking.trim())}</div></details>` : "";
16639
+ const text = item.text.trim() === "" ? "" : `<div class="md">${markdown2.parse(item.text.trim(), { async: false })}</div>`;
16640
+ const note = item.note === null ? "" : `<div class="note">${escapeHtml(oneLine(item.note))}</div>`;
16641
+ body.push(`<section class="msg assistant"><div class="role">Assistant</div>${thinking}${text}${note}</section>`);
16642
+ } else {
16643
+ const status = toolStatus(item);
16644
+ const output = toolOutput(item);
16645
+ const heading = [
16646
+ `<b>Tool</b> ${escapeHtml(item.name)}`,
16647
+ item.summary === "" ? "" : `<span class="args">${escapeHtml(oneLine(item.summary))}</span>`,
16648
+ status === "ok" ? "" : `<span class="status">[${status}]</span>`,
16649
+ item.durationMs === null ? "" : `<span class="duration">(${formatDuration(item.durationMs)})</span>`
16650
+ ].filter(Boolean).join(" ");
16651
+ body.push(`<details class="tool ${status}"><summary>${heading}</summary>${item.detail === null || item.detail === "" ? "" : `<pre>${escapeHtml(item.detail)}</pre>`}${output === "" ? "" : `<div class="label">${status === "running" ? "Output so far" : "Result"}</div><pre>${escapeHtml(output)}</pre>`}${item.note === null ? "" : `<div class="note">${escapeHtml(oneLine(item.note))}</div>`}${renderImages(item.images, embedded)}</details>`);
16652
+ }
16653
+ }
16654
+ const content = `<!doctype html>
16655
+ <html lang="en">
16656
+ <head>
16657
+ <meta charset="utf-8">
16658
+ <meta http-equiv="Content-Security-Policy" content="${CSP}">
16659
+ <meta name="viewport" content="width=device-width, initial-scale=1">
16660
+ <title>${title}</title>
16661
+ <style>${STYLE}</style>
16662
+ </head>
16663
+ <body>
16664
+ <main>
16665
+ <h1>${title}</h1>
16666
+ <p class="meta">${escapeHtml(oneLine(source.model))} \xB7 ${escapeHtml(oneLine(source.cwd))} \xB7 ${escapeHtml(source.exportedAt.toISOString())}</p>
16667
+ ${body.join(`
16668
+ `)}
16669
+ </main>
16670
+ </body>
16671
+ </html>
16672
+ `;
16673
+ return { content, skippedImages: skipped };
16674
+ }
16675
+ var MAX_EMBEDDED_IMAGE_BYTES, SAFE_IMAGE_TYPE, SAFE_LINK, BASE64_SLICE_BYTES, CSP = "default-src 'none'; img-src data:; style-src 'unsafe-inline'", STYLE = `
16676
+ :root{color-scheme:light dark;--bg:#fff;--fg:#1f2328;--muted:#656d76;--border:#d0d7de;--user:#eef4ff;--code:#f6f8fa}
16677
+ @media(prefers-color-scheme:dark){:root{--bg:#0d1117;--fg:#e6edf3;--muted:#8b949e;--border:#30363d;--user:#16243a;--code:#161b22}}
16678
+ body{margin:0;background:var(--bg);color:var(--fg);font:15px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif}
16679
+ main{max-width:860px;margin:0 auto;padding:24px 16px 64px}
16680
+ h1{font-size:1.5rem;margin:0 0 4px}
16681
+ .meta{color:var(--muted);font-size:.85rem;margin:0 0 24px}
16682
+ .msg{margin:16px 0;padding:12px 16px;border:1px solid var(--border);border-radius:12px}
16683
+ .msg.user{background:var(--user)}
16684
+ .role{font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
16685
+ .text{white-space:pre-wrap;overflow-wrap:anywhere}
16686
+ .system{text-align:center;color:var(--muted);font-size:.85rem;margin:16px 0}
16687
+ .md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}
16688
+ .md pre,pre{background:var(--code);border-radius:8px;padding:10px 12px;overflow:auto;font-size:.85rem;white-space:pre-wrap;overflow-wrap:anywhere}
16689
+ .md code{background:var(--code);border-radius:4px;padding:1px 4px}.md pre code{background:none;padding:0}
16690
+ .md table{border-collapse:collapse}.md th,.md td{border:1px solid var(--border);padding:4px 8px}
16691
+ .md blockquote{margin:0;padding-left:12px;border-left:3px solid var(--border);color:var(--muted)}
16692
+ details{margin:8px 0}summary{cursor:pointer;color:var(--muted)}
16693
+ details.tool{border:1px solid var(--border);border-radius:8px;padding:6px 12px;margin:12px 0}
16694
+ details.tool.error>summary .status{color:#cf222e}
16695
+ .label{font-size:.75rem;color:var(--muted);margin-top:8px}
16696
+ .note{color:var(--muted);font-style:italic;margin-top:6px}
16697
+ figure{margin:8px 0}img{max-width:100%;height:auto;border-radius:8px}figcaption,.placeholder{color:var(--muted);font-size:.8rem}
16698
+ `, escapeHtml = (text) => text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;"), markdown2;
16699
+ var init_conversation_export_html = __esm(() => {
16700
+ init_marked_esm();
16701
+ MAX_EMBEDDED_IMAGE_BYTES = 32 * 1024 * 1024;
16702
+ SAFE_IMAGE_TYPE = /^image\/(png|jpeg|webp|gif)$/i;
16703
+ SAFE_LINK = /^(https?:|mailto:)/i;
16704
+ BASE64_SLICE_BYTES = 3 * 16 * 1024;
16705
+ markdown2 = new F({
16706
+ gfm: true,
16707
+ breaks: true,
16708
+ renderer: {
16709
+ html: ({ text }) => escapeHtml(text),
16710
+ link({ href, title, tokens }) {
16711
+ const label = this.parser.parseInline(tokens);
16712
+ if (!SAFE_LINK.test(href.trim()))
16713
+ return label;
16714
+ const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
16715
+ return `<a href="${escapeHtml(href)}"${titleAttr} rel="noopener noreferrer" target="_blank">${label}</a>`;
16716
+ },
16717
+ image({ href, text }) {
16718
+ const label = `[image: ${escapeHtml(text || href)}]`;
16719
+ return SAFE_LINK.test(href.trim()) ? `<a href="${escapeHtml(href)}" rel="noopener noreferrer" target="_blank">${label}</a>` : label;
16720
+ }
16721
+ }
16722
+ });
16723
+ });
16724
+
16725
+ // packages/core/src/conversation-export.ts
16726
+ function copyText(item) {
16727
+ if (item.type === "user")
16728
+ return userText2(item);
16729
+ if (item.type === "assistant")
16730
+ return item.text.trim();
16731
+ return "";
16732
+ }
16733
+ function lastAnswerText(items) {
16734
+ for (let i = items.length - 1;i >= 0; i--) {
16735
+ const item = items[i];
16736
+ if (item.type !== "assistant")
16737
+ continue;
16738
+ const text = copyText(item);
16739
+ if (text !== "")
16740
+ return text;
16741
+ }
16742
+ return null;
16743
+ }
16744
+ function exportFormatFromPath(path) {
16745
+ const extension = /\.(md|html|json)$/i.exec(path)?.[1]?.toLowerCase();
16746
+ return extension === "md" ? "markdown" : extension === "html" ? "html" : extension === "json" ? "json" : null;
16747
+ }
16748
+ function exportFileName(title, format, at) {
16749
+ const cleaned = title.replace(/[\\/:*?"<>|\u0000-\u001f\u007f]/g, "-").replace(/\s+/g, " ").replace(/-{2,}/g, "-");
16750
+ const safe = Array.from(cleaned).slice(0, MAX_FILE_TITLE_CHARS).join("").replace(/^[\s.-]+|[\s.-]+$/g, "") || FALLBACK_EXPORT_TITLE;
16751
+ const pad = (value, width = 2) => String(value).padStart(width, "0");
16752
+ const stamp = `${pad(at.getFullYear(), 4)}${pad(at.getMonth() + 1)}${pad(at.getDate())}-${pad(at.getHours())}${pad(at.getMinutes())}${pad(at.getSeconds())}`;
16753
+ return `${safe}-${stamp}.${EXPORT_EXTENSIONS[format]}`;
16754
+ }
16755
+ async function exportConversation(format, source, options) {
16756
+ if (source.items.length === 0)
16757
+ throw new Error("Nothing to export yet - start a conversation first");
16758
+ const extension = EXPORT_EXTENSIONS[format];
16759
+ const mimeType = MIME_TYPES[format];
16760
+ if (format === "html") {
16761
+ const { content, skippedImages } = await exportHtml(source, options);
16762
+ return { content, mimeType, extension, skippedImages };
16763
+ }
16764
+ const content = format === "markdown" ? exportMarkdown(source, options) : exportJson(source, options);
16765
+ return { content, mimeType, extension, skippedImages: 0 };
16766
+ }
16767
+ function block(content) {
16768
+ let longest = 0;
16769
+ for (const run of content.matchAll(/`+/g))
16770
+ longest = Math.max(longest, run[0].length);
16771
+ const marks = "`".repeat(Math.max(3, longest + 1));
16772
+ return `${marks}
16773
+ ${content}
16774
+ ${marks}`;
16775
+ }
16776
+ function exportMarkdown(source, options) {
16777
+ const out = [
16778
+ `# ${oneLine(source.title) || FALLBACK_EXPORT_TITLE}`,
16779
+ "",
16780
+ `- **Model:** ${oneLine(source.model)}`,
16781
+ `- **Workspace:** ${oneLine(source.cwd)}`,
16782
+ `- **Exported:** ${source.exportedAt.toISOString()}`,
16783
+ ""
16784
+ ];
16785
+ let role = null;
16786
+ const heading = (next) => {
16787
+ if (role === next)
16788
+ return;
16789
+ role = next;
16790
+ out.push("---", "", next === "user" ? "## User" : "## Assistant", "");
16791
+ };
16792
+ for (const item of source.items) {
16793
+ if (item.type === "system") {
16794
+ role = null;
16795
+ out.push("---", "", `*${escapeInline(oneLine(item.text))}*`, "");
16796
+ } else if (item.type === "user") {
16797
+ heading("user");
16798
+ const text = userText2(item);
16799
+ if (text !== "")
16800
+ out.push(text, "");
16801
+ for (const image of item.images ?? [])
16802
+ out.push(`> [image] ${escapeInline(imageLabel(image))}`, "");
16803
+ } else if (item.type === "assistant") {
16804
+ heading("assistant");
16805
+ if (options.includeThinking && item.thinking.trim() !== "")
16806
+ out.push("<details>", "<summary>Thinking</summary>", "", item.thinking.trim(), "", "</details>", "");
16807
+ if (item.text.trim() !== "")
16808
+ out.push(item.text.trim(), "");
16809
+ if (item.note !== null)
16810
+ out.push(`> ${escapeInline(oneLine(item.note))}`, "");
16811
+ } else {
16812
+ heading("assistant");
16813
+ out.push(...markdownTool(item));
16814
+ }
16815
+ }
16816
+ return `${out.join(`
16817
+ `).trimEnd()}
16818
+ `;
16819
+ }
16820
+ function markdownTool(item) {
16821
+ const status = toolStatus(item);
16822
+ const label = [
16823
+ `Tool: ${item.name}`,
16824
+ item.summary === "" ? "" : `\xB7 ${oneLine(item.summary)}`,
16825
+ status === "ok" ? "" : `[${status}]`,
16826
+ item.durationMs === null ? "" : `(${formatDuration(item.durationMs)})`
16827
+ ].filter(Boolean).join(" ");
16828
+ const lines = ["<details>", `<summary>${escapeInline(label)}</summary>`, ""];
16829
+ if (item.detail !== null && item.detail !== "")
16830
+ lines.push(block(item.detail), "");
16831
+ const output = toolOutput(item);
16832
+ if (output !== "")
16833
+ lines.push(status === "running" ? "Output so far:" : "Result:", "", block(output), "");
16834
+ if (item.note !== null)
16835
+ lines.push(`> ${escapeInline(oneLine(item.note))}`, "");
16836
+ for (const image of item.images ?? [])
16837
+ lines.push(`> [image] ${escapeInline(imageLabel(image))}`, "");
16838
+ lines.push("</details>", "");
16839
+ return lines;
16840
+ }
16841
+ function exportJson(source, options) {
16842
+ const items = source.items.map((item) => {
16843
+ switch (item.type) {
16844
+ case "user":
16845
+ return {
16846
+ type: "user",
16847
+ text: userText2(item),
16848
+ images: (item.images ?? []).map(({ name, mimeType, width, height, bytes }) => ({
16849
+ name,
16850
+ mimeType,
16851
+ width,
16852
+ height,
16853
+ bytes
16854
+ }))
16855
+ };
16856
+ case "assistant":
16857
+ return {
16858
+ type: "assistant",
16859
+ text: item.text,
16860
+ ...options.includeThinking && item.thinking.trim() !== "" ? { thinking: item.thinking } : {},
16861
+ stopReason: item.stopReason,
16862
+ note: item.note
16863
+ };
16864
+ case "tool":
16865
+ return {
16866
+ type: "tool",
16867
+ name: item.name,
16868
+ summary: item.summary,
16869
+ detail: item.detail,
16870
+ status: item.phase,
16871
+ isError: item.isError,
16872
+ result: toolOutput(item),
16873
+ durationMs: item.durationMs,
16874
+ note: item.note,
16875
+ images: (item.images ?? []).map(({ name, mimeType, width, height, bytes }) => ({
16876
+ name,
16877
+ mimeType,
16878
+ width,
16879
+ height,
16880
+ bytes
16881
+ }))
16882
+ };
16883
+ default:
16884
+ return { type: "system", text: item.text };
16885
+ }
16886
+ });
16887
+ return `${JSON.stringify({
16888
+ format: "neko-conversation",
16889
+ version: 1,
16890
+ session: {
16891
+ id: source.sessionId,
16892
+ title: source.title,
16893
+ model: source.model,
16894
+ cwd: source.cwd,
16895
+ exportedAt: source.exportedAt.toISOString()
16896
+ },
16897
+ items
16898
+ }, null, 2)}
16899
+ `;
16900
+ }
16901
+ var EXPORT_EXTENSIONS, MIME_TYPES, MAX_FILE_TITLE_CHARS = 60, escapeInline = (text) => text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16902
+ var init_conversation_export = __esm(() => {
16903
+ init_conversation_export_html();
16904
+ init_conversation_export_html();
16905
+ EXPORT_EXTENSIONS = { markdown: "md", html: "html", json: "json" };
16906
+ MIME_TYPES = {
16907
+ markdown: "text/markdown;charset=utf-8",
16908
+ html: "text/html;charset=utf-8",
16909
+ json: "application/json;charset=utf-8"
16910
+ };
16911
+ });
16912
+
16913
+ // packages/tui/src/clipboard-write.ts
16914
+ import { spawn as spawn2 } from "child_process";
16915
+ import { getNativeClipboard } from "@earendil-works/pi-tui";
16916
+ function runClipboardCommand(command, args, input) {
16917
+ const { promise, resolve } = Promise.withResolvers();
16918
+ const child = spawn2(command, args, { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
16919
+ const timer = setTimeout(() => {
16920
+ child.kill("SIGKILL");
16921
+ resolve(false);
16922
+ }, COMMAND_TIMEOUT_MS);
16923
+ child.on("error", () => {
16924
+ clearTimeout(timer);
16925
+ resolve(false);
16926
+ });
16927
+ child.on("close", (code) => {
16928
+ clearTimeout(timer);
16929
+ resolve(code === 0);
16930
+ });
16931
+ child.stdin.on("error", () => {});
16932
+ child.stdin.end(input);
16933
+ return promise;
16934
+ }
16935
+ async function copyToClipboard(text, deps) {
16936
+ const platform = deps.platform ?? process.platform;
16937
+ const env = deps.env ?? process.env;
16938
+ const native = "native" in deps ? deps.native : getNativeClipboard();
16939
+ const run = deps.run ?? runClipboardCommand;
16940
+ let method = null;
16941
+ if (platform !== "linux" && native?.setText !== undefined) {
16942
+ try {
16943
+ await native.setText(text);
16944
+ method = "native";
16945
+ } catch {}
16946
+ }
16947
+ if (method === null) {
16948
+ const tools = [];
16949
+ if (platform === "darwin")
16950
+ tools.push(["pbcopy", []]);
16951
+ else if (platform === "win32")
16952
+ tools.push([
16953
+ "powershell.exe",
16954
+ [
16955
+ "-NoProfile",
16956
+ "-NonInteractive",
16957
+ "-Command",
16958
+ "$t=[IO.StreamReader]::new([Console]::OpenStandardInput(),[Text.UTF8Encoding]::new($false)).ReadToEnd();Set-Clipboard -Value $t"
16959
+ ]
16960
+ ]);
16961
+ else {
16962
+ if (env.TERMUX_VERSION)
16963
+ tools.push(["termux-clipboard-set", []]);
16964
+ if (env.WAYLAND_DISPLAY)
16965
+ tools.push(["wl-copy", []]);
16966
+ if (env.DISPLAY)
16967
+ tools.push(["xclip", ["-selection", "clipboard"]], ["xsel", ["--clipboard", "--input"]]);
16968
+ }
16969
+ for (const [command, args] of tools) {
16970
+ if (await run(command, args, text)) {
16971
+ method = "command";
16972
+ break;
16973
+ }
16974
+ }
16975
+ }
16976
+ const remote = Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);
16977
+ let osc52Sent = false;
16978
+ if (method === null || remote) {
16979
+ const encoded = Buffer.from(text).toString("base64");
16980
+ if (encoded.length <= OSC52_MAX_BASE64_LENGTH) {
16981
+ deps.osc52(`\x1B]52;c;${encoded}\x07`);
16982
+ osc52Sent = true;
16983
+ }
16984
+ }
16985
+ if (method === null && !osc52Sent)
16986
+ throw new Error(`Clipboard unavailable: no clipboard tool worked and ${text.length} chars is too large for OSC 52. Use /export to save it to a file.`);
16987
+ return { method: method ?? "osc52", osc52Sent };
16988
+ }
16989
+ async function copyLastAnswer(items, deps) {
16990
+ const text = lastAnswerText(items);
16991
+ if (text === null)
16992
+ return { level: "warning", message: "Nothing to copy yet: no assistant answer in this session." };
16993
+ try {
16994
+ const result = await copyToClipboard(text, deps);
16995
+ return {
16996
+ level: "info",
16997
+ message: result.osc52Sent ? `Sent to terminal clipboard via OSC 52 (${text.length} chars); your terminal must allow it` : `Copied last response (${text.length} chars)`
16998
+ };
16999
+ } catch (error) {
17000
+ return { level: "error", message: error instanceof Error ? error.message : String(error) };
17001
+ }
17002
+ }
17003
+ var OSC52_MAX_BASE64_LENGTH = 1e5, COMMAND_TIMEOUT_MS = 3000;
17004
+ var init_clipboard_write = __esm(() => {
17005
+ init_conversation_export();
17006
+ });
17007
+
17008
+ // packages/tui/src/components/assistant-message.ts
17009
+ import { Container, Markdown, MouseRegion, Spacer, Text as Text2 } from "@earendil-works/pi-tui";
17010
+ var THINKING_COLLAPSED_LABEL = "\u2727 Thinking\u2026 (click to expand)", AssistantMessageComponent;
17011
+ var init_assistant_message = __esm(() => {
17012
+ init_theme();
17013
+ AssistantMessageComponent = class AssistantMessageComponent extends Container {
17014
+ #renderTheme = getActiveThemeMode();
17015
+ #lastContent;
17016
+ #isStreaming = false;
17017
+ #thinkingExpanded = false;
17018
+ #renderWidth = 80;
17019
+ constructor(content, isStreaming = false) {
17020
+ super();
17021
+ if (content !== undefined)
17022
+ this.updateContent(content, isStreaming);
17023
+ }
17024
+ render(width) {
17025
+ if (this.#renderTheme !== getActiveThemeMode()) {
17026
+ this.#renderTheme = getActiveThemeMode();
17027
+ this.#rebuild();
17028
+ }
17029
+ this.#renderWidth = width;
17030
+ return super.render(width);
17031
+ }
17032
+ #highlightWidth() {
17033
+ return Math.max(10, this.#renderWidth - 4);
17034
+ }
17035
+ updateContent(content, isStreaming = this.#isStreaming) {
17036
+ this.#lastContent = content;
17037
+ this.#isStreaming = isStreaming;
17038
+ this.#rebuild();
17039
+ }
17040
+ setThinkingExpanded(expanded) {
17041
+ this.#thinkingExpanded = expanded;
17042
+ if (this.#lastContent !== undefined)
17043
+ this.#rebuild();
17044
+ }
17045
+ #rebuild() {
17046
+ const content = this.#lastContent;
17047
+ this.clear();
17048
+ if (content === undefined)
17049
+ return;
17050
+ if (content.thinking.trim() !== "") {
17051
+ const expanded = this.#thinkingExpanded;
17052
+ const thinkingComponent = expanded ? new Markdown(content.thinking.trim(), 1, 0, getMarkdownTheme(() => this.#highlightWidth()), {
17053
+ color: theme.thinking,
17054
+ italic: true
17055
+ }) : new Text2(theme.thinking(THINKING_COLLAPSED_LABEL), 1, 0);
17056
+ this.addChild(new MouseRegion(thinkingComponent, (event) => {
17057
+ if (event.type !== "click" || event.button !== "left")
17058
+ return;
17059
+ this.setThinkingExpanded(!expanded);
17060
+ return { handled: true };
17061
+ }));
17062
+ }
17063
+ if (content.text.trim() !== "") {
17064
+ this.addChild(new Markdown(content.text.trim(), 1, 0, getMarkdownTheme(() => this.#highlightWidth())));
17065
+ }
17066
+ if (content.note !== null) {
17067
+ this.addChild(new Spacer(1));
17068
+ this.addChild(new Text2(theme.error(content.note), 1, 0));
17069
+ }
17070
+ }
17071
+ };
17072
+ });
17073
+
17074
+ // packages/tui/src/components/editor.ts
17075
+ import {
17076
+ CURSOR_MARKER,
17077
+ Editor,
17078
+ isKeyRelease,
17079
+ isKeyRepeat,
17080
+ matchesKey as matchesKey3,
17081
+ stripTerminalSequences
17082
+ } from "@earendil-works/pi-tui";
17083
+ var BoundedEditor;
17084
+ var init_editor = __esm(() => {
17085
+ BoundedEditor = class BoundedEditor extends Editor {
17086
+ maxRows = 7;
17087
+ isImageReference = () => false;
17088
+ onClearDraft;
17089
+ #lastEscape = 0;
17090
+ #completionEpoch = 0;
17091
+ #completionProvider;
17092
+ setAutocompleteProvider(provider) {
17093
+ this.#completionEpoch++;
17094
+ const wrapped = {
17095
+ triggerCharacters: provider.triggerCharacters,
17096
+ shouldTriggerFileCompletion: provider.shouldTriggerFileCompletion?.bind(provider),
17097
+ getSuggestions: provider.getSuggestions.bind(provider),
17098
+ applyCompletion: (...args) => {
17099
+ const result = provider.applyCompletion(...args);
17100
+ if (args[4].startsWith("@") && args[3].label.endsWith("/")) {
17101
+ const epoch = this.#completionEpoch;
17102
+ queueMicrotask(() => {
17103
+ const cursor = this.getCursor();
17104
+ if (epoch === this.#completionEpoch && this.getText() === result.lines.join(`
17105
+ `) && cursor.line === result.cursorLine && cursor.col === result.cursorCol)
17106
+ super.handleInput("\t");
17107
+ });
17108
+ }
17109
+ return result;
17110
+ }
17111
+ };
17112
+ this.#completionProvider = wrapped;
17113
+ super.setAutocompleteProvider(wrapped);
17114
+ }
17115
+ resetEscapeSequence() {
17116
+ this.#lastEscape = 0;
17117
+ }
17118
+ setText(text) {
17119
+ this.#completionEpoch++;
17120
+ this.resetEscapeSequence();
17121
+ super.setText(text);
17122
+ this.#flushHistory();
17123
+ }
17124
+ setHistory(entries) {
17125
+ if (this["historyIndex"] > -1) {
17126
+ this.#pendingHistory = entries;
17127
+ return;
17128
+ }
17129
+ this.#pendingHistory = undefined;
17130
+ const current = this["history"];
17131
+ if (current.length === entries.length && current.every((entry, i) => entry === entries[i]))
17132
+ return;
17133
+ this["history"] = [...entries];
17134
+ }
17135
+ #pendingHistory;
17136
+ #flushHistory() {
17137
+ if (this.#pendingHistory !== undefined && this["historyIndex"] === -1)
17138
+ this.setHistory(this.#pendingHistory);
17139
+ }
17140
+ handleInput(data) {
17141
+ if (isKeyRelease(data))
17142
+ return;
17143
+ this.#flushHistory();
17144
+ this.#completionEpoch++;
17145
+ if (matchesKey3(data, "escape") && this.isShowingAutocomplete()) {
17146
+ this.resetEscapeSequence();
17147
+ super.handleInput(data);
17148
+ return;
17149
+ }
17150
+ if (matchesKey3(data, "escape")) {
17151
+ if (this.#completionProvider)
17152
+ super.setAutocompleteProvider(this.#completionProvider);
17153
+ if (isKeyRepeat(data))
17154
+ return;
17155
+ const now = Date.now();
17156
+ if (this.#lastEscape && now - this.#lastEscape <= 400) {
17157
+ this.#lastEscape = 0;
17158
+ this.setText("");
17159
+ this.onClearDraft?.();
17160
+ return;
17161
+ }
17162
+ this.#lastEscape = now;
17163
+ super.handleInput(data);
17164
+ return;
17165
+ }
17166
+ this.#lastEscape = 0;
15121
17167
  const backward = matchesKey3(data, "backspace");
15122
17168
  const forward = matchesKey3(data, "delete") || matchesKey3(data, "ctrl+d");
15123
17169
  if (backward || forward) {
@@ -15186,6 +17232,8 @@ var init_labels = __esm(() => {
15186
17232
  { name: "help", description: "Show keyboard shortcuts and commands" },
15187
17233
  { name: "version", description: "View versions and check for updates" },
15188
17234
  { name: "compact", description: "Compact context (/compact optional instructions)" },
17235
+ { name: "copy", description: "Copy the last assistant response" },
17236
+ { name: "export", description: "Export session (/export path.md|.html|.json [--thinking])" },
15189
17237
  { name: "exit", description: "Exit neko TUI" },
15190
17238
  { name: "new", description: "Create a new session" },
15191
17239
  { name: "sessions", description: "Switch or create a session" },
@@ -15990,6 +18038,17 @@ class ThemedTruncatedText {
15990
18038
  return new TruncatedText(this.#content(), this.#paddingX, this.#paddingY).render(width);
15991
18039
  }
15992
18040
  }
18041
+
18042
+ class ThemedWrappedText {
18043
+ #content;
18044
+ constructor(content) {
18045
+ this.#content = content;
18046
+ }
18047
+ invalidate() {}
18048
+ render(width) {
18049
+ return new Text4(this.#content(), 1, 0).render(width);
18050
+ }
18051
+ }
15993
18052
  var ThemedText;
15994
18053
  var init_themed_text = __esm(() => {
15995
18054
  ThemedText = class ThemedText extends Text4 {
@@ -16011,6 +18070,103 @@ var init_themed_text = __esm(() => {
16011
18070
  };
16012
18071
  });
16013
18072
 
18073
+ // packages/tui/src/components/diff-view.ts
18074
+ function parseDiffLine(line, format = "edit") {
18075
+ if (format === "write") {
18076
+ return line.startsWith("+ ") ? { prefix: "+", lineNum: "", content: line.slice(2) } : null;
18077
+ }
18078
+ const match = /^([+\- ])( *\d+) (.*)$/.exec(line);
18079
+ if (match === null)
18080
+ return null;
18081
+ const first = match[1];
18082
+ const prefix = first === "+" || first === "-" ? first : " ";
18083
+ return { prefix, lineNum: match[2] ?? "", content: match[3] ?? "" };
18084
+ }
18085
+ function parseDiffLines(diff, format = "edit") {
18086
+ return diff.split(`
18087
+ `).map((line) => {
18088
+ const parsed = parseDiffLine(line, format);
18089
+ if (parsed === null)
18090
+ return { kind: "raw", text: line };
18091
+ const kind = parsed.prefix === "+" ? "add" : parsed.prefix === "-" ? "del" : "context";
18092
+ return { kind, lineNum: parsed.lineNum, content: parsed.content };
18093
+ });
18094
+ }
18095
+ function diffTargetPath(name, summary, detail) {
18096
+ if (name === "edit") {
18097
+ const path = summary.replace(/ \(\d+ edits?\)$/, "");
18098
+ return path === "" ? undefined : path;
18099
+ }
18100
+ if (name === "write") {
18101
+ if (detail !== null) {
18102
+ const first = detail.split(`
18103
+ `, 1)[0] ?? "";
18104
+ if (first !== "")
18105
+ return first;
18106
+ }
18107
+ return summary === "" ? undefined : summary;
18108
+ }
18109
+ return;
18110
+ }
18111
+ function highlightDocuments(parsed, lang) {
18112
+ const newContents = [];
18113
+ const oldContents = [];
18114
+ for (const line of parsed) {
18115
+ if (line.kind === "raw")
18116
+ continue;
18117
+ if (line.kind !== "del")
18118
+ newContents.push(line.content);
18119
+ if (line.kind !== "add")
18120
+ oldContents.push(line.content);
18121
+ }
18122
+ const newLines = highlightCodeToSegments(newContents.join(`
18123
+ `), lang);
18124
+ const oldLines = highlightCodeToSegments(oldContents.join(`
18125
+ `), lang);
18126
+ if (newLines === null || oldLines === null)
18127
+ return null;
18128
+ return { newLines, oldLines };
18129
+ }
18130
+ function styleSegments(segments) {
18131
+ return segments.map((s) => s.slot === "plain" ? theme.codeFg(s.text) : theme[s.slot](s.text)).join("");
18132
+ }
18133
+ function paintChangedLine(kind, gutter, content) {
18134
+ const bg = diffBackgroundAnsi(kind === "add" ? "added" : "removed");
18135
+ return `${bg}${theme.dim(gutter)}${bg}${content}\x1B[49m`;
18136
+ }
18137
+ function highlightDiffLines(diff, lang, format = "edit") {
18138
+ const parsed = parseDiffLines(diff, format);
18139
+ const documents = highlightDocuments(parsed, lang);
18140
+ if (documents === null)
18141
+ return highlightCodeToAnsiLines(diff, "diff");
18142
+ const rendered = [];
18143
+ let newIndex = 0;
18144
+ let oldIndex = 0;
18145
+ for (const line of parsed) {
18146
+ if (line.kind === "raw") {
18147
+ rendered.push(theme.dim(line.text));
18148
+ continue;
18149
+ }
18150
+ const sign = line.kind === "add" ? "+" : line.kind === "del" ? "-" : " ";
18151
+ const gutter = `${sign}${line.lineNum} `;
18152
+ if (line.kind === "del") {
18153
+ rendered.push(paintChangedLine("del", gutter, styleSegments(documents.oldLines[oldIndex++] ?? [])));
18154
+ continue;
18155
+ }
18156
+ if (line.kind === "add") {
18157
+ rendered.push(paintChangedLine("add", gutter, styleSegments(documents.newLines[newIndex++] ?? [])));
18158
+ continue;
18159
+ }
18160
+ rendered.push(`${theme.dim(gutter)}${styleSegments(documents.newLines[newIndex++] ?? [])}`);
18161
+ oldIndex++;
18162
+ }
18163
+ return rendered;
18164
+ }
18165
+ var init_diff_view = __esm(() => {
18166
+ init_slots();
18167
+ init_syntax();
18168
+ });
18169
+
16014
18170
  // packages/tui/src/components/tool-execution.ts
16015
18171
  import { Box, Container as Container3, MouseRegion as MouseRegion2, Text as Text5 } from "@earendil-works/pi-tui";
16016
18172
  function currentToolFrame() {
@@ -16041,15 +18197,23 @@ class ToolSpinnerTicker {
16041
18197
  this.#timer = undefined;
16042
18198
  }
16043
18199
  }
18200
+ function diffCountSuffix(state) {
18201
+ if (state.diffAdded === null)
18202
+ return "";
18203
+ const removed = state.diffRemoved !== null && state.diffRemoved > 0 ? `/-${state.diffRemoved}` : "";
18204
+ return ` (+${state.diffAdded}${removed})`;
18205
+ }
16044
18206
  function clipLines(text, maxLines) {
16045
18207
  const lines = text.split(`
16046
18208
  `);
16047
18209
  return { visible: lines.slice(0, maxLines).join(`
16048
18210
  `), rest: Math.max(0, lines.length - maxLines) };
16049
18211
  }
16050
- var SPINNER_FRAMES, spinnerFrame = 0, ToolExecutionComponent;
18212
+ var SPINNER_FRAMES, spinnerFrame = 0, DIFF_MAX_LINES = 50, ToolExecutionComponent;
16051
18213
  var init_tool_execution = __esm(() => {
16052
18214
  init_theme();
18215
+ init_syntax();
18216
+ init_diff_view();
16053
18217
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
16054
18218
  ToolExecutionComponent = class ToolExecutionComponent extends Container3 {
16055
18219
  #renderTheme = getActiveThemeMode();
@@ -16103,16 +18267,38 @@ var init_tool_execution = __esm(() => {
16103
18267
  }
16104
18268
  rebuild() {
16105
18269
  const state = this.#state;
16106
- const parts = [`${theme.toolTitle(`\u26A1 ${state.name}`)}`, theme.dim(state.summary), this.#statusLine(state.phase)];
18270
+ const parts = [
18271
+ `${theme.toolTitle(`\u26A1 ${state.name}`)}`,
18272
+ theme.dim(state.summary + diffCountSuffix(state)),
18273
+ this.#statusLine(state.phase)
18274
+ ];
16107
18275
  let text = parts.join(" ");
16108
- if (this.#expanded && state.detail !== null) {
16109
- const detail = clipLines(state.detail, 20);
16110
- text += `
18276
+ if (this.#expanded) {
18277
+ const detail = state.detail;
18278
+ if (detail !== null && !(state.diff !== null && state.name === "write" && !state.diffTruncated)) {
18279
+ const clipped = clipLines(detail, 20);
18280
+ text += `
16111
18281
  ${theme.dim("---- Arguments ----")}
16112
- ${detail.visible}`;
16113
- if (detail.rest > 0)
18282
+ ${clipped.visible}`;
18283
+ if (clipped.rest > 0)
18284
+ text += `
18285
+ ${theme.dim(`... ${clipped.rest} more lines`)}`;
18286
+ }
18287
+ if (state.diff !== null) {
18288
+ const clipped = clipLines(state.diff, DIFF_MAX_LINES);
18289
+ const lang = languageForPath(diffTargetPath(state.name, state.summary, state.detail));
18290
+ const format = state.name === "write" ? "write" : "edit";
16114
18291
  text += `
16115
- ${theme.dim(`... ${detail.rest} more lines`)}`;
18292
+ ${theme.dim("---- Diff ----")}
18293
+ ${highlightDiffLines(clipped.visible, lang, format).join(`
18294
+ `)}`;
18295
+ if (state.diffTruncated)
18296
+ text += `
18297
+ ${theme.dim("\u2026 Diff preview truncated (line or byte limit)")}`;
18298
+ if (clipped.rest > 0)
18299
+ text += `
18300
+ ${theme.dim(`\u2026 +${clipped.rest} more lines`)}`;
18301
+ }
16116
18302
  }
16117
18303
  const body = state.phase === "running" ? state.output : state.result;
16118
18304
  if (!this.#expanded && body !== null && body !== "") {
@@ -16299,6 +18485,90 @@ function followTerminalTheme(ui, apply) {
16299
18485
  }
16300
18486
  var THEME_QUERY_TIMEOUT_MS = 100;
16301
18487
 
18488
+ // packages/tui/src/export-command.ts
18489
+ import { open as open2, unlink as unlink2 } from "fs/promises";
18490
+ import { homedir as homedir6 } from "os";
18491
+ import { resolve as resolve4 } from "path";
18492
+ function parseExportArgs(input) {
18493
+ const words = [];
18494
+ let word = "";
18495
+ let quote = "";
18496
+ let quoted = false;
18497
+ let active = false;
18498
+ for (const c of input) {
18499
+ if (quote !== "") {
18500
+ if (c === quote)
18501
+ quote = "";
18502
+ else
18503
+ word += c;
18504
+ } else if (c === '"' || c === "'") {
18505
+ quote = c;
18506
+ quoted = true;
18507
+ active = true;
18508
+ } else if (/\s/.test(c)) {
18509
+ if (active)
18510
+ words.push({ text: word, quoted });
18511
+ word = "";
18512
+ quoted = false;
18513
+ active = false;
18514
+ } else {
18515
+ word += c;
18516
+ active = true;
18517
+ }
18518
+ }
18519
+ if (quote !== "")
18520
+ throw new Error(`Unterminated quote. ${EXPORT_USAGE}`);
18521
+ if (active)
18522
+ words.push({ text: word, quoted });
18523
+ let includeThinking = false;
18524
+ let path;
18525
+ for (const { text, quoted: wasQuoted } of words) {
18526
+ if (!wasQuoted && text === "--thinking")
18527
+ includeThinking = true;
18528
+ else if (!wasQuoted && text.startsWith("--"))
18529
+ throw new Error(`Unknown option ${text}. ${EXPORT_USAGE}`);
18530
+ else if (path === undefined && text !== "")
18531
+ path = text;
18532
+ else
18533
+ throw new Error(EXPORT_USAGE);
18534
+ }
18535
+ return { path, includeThinking };
18536
+ }
18537
+ async function exportToFile(input) {
18538
+ const format = input.path === undefined ? "markdown" : exportFormatFromPath(input.path);
18539
+ if (format === null)
18540
+ throw new Error("Unsupported export format: use a .md, .html or .json path");
18541
+ const target = resolve4(input.cwd, input.path === undefined ? exportFileName(input.source.title, format, input.source.exportedAt) : input.path.startsWith("~/") ? homedir6() + input.path.slice(1) : input.path);
18542
+ let handle;
18543
+ try {
18544
+ handle = await open2(target, "wx");
18545
+ } catch (error) {
18546
+ const code = error.code;
18547
+ if (code === "EEXIST")
18548
+ throw new Error(`File already exists: ${target}. Choose another path.`);
18549
+ if (code === "ENOENT")
18550
+ throw new Error(`Directory does not exist: ${target}`);
18551
+ throw error;
18552
+ }
18553
+ try {
18554
+ const result = await exportConversation(format, input.source, {
18555
+ includeThinking: input.includeThinking,
18556
+ ...input.loadImage ? { loadImage: input.loadImage } : {}
18557
+ });
18558
+ await handle.writeFile(result.content, "utf8");
18559
+ return { path: target, skippedImages: result.skippedImages };
18560
+ } catch (error) {
18561
+ await unlink2(target).catch(() => {});
18562
+ throw error;
18563
+ } finally {
18564
+ await handle.close().catch(() => {});
18565
+ }
18566
+ }
18567
+ var EXPORT_USAGE = "Usage: /export [path.md|path.html|path.json] [--thinking]";
18568
+ var init_export_command = __esm(() => {
18569
+ init_conversation_export();
18570
+ });
18571
+
16302
18572
  // packages/core/src/file-mentions.ts
16303
18573
  function mentionAt(text, cursor) {
16304
18574
  const before = text.slice(0, cursor);
@@ -16363,7 +18633,7 @@ function fileCompletion(commands, root, notice, search) {
16363
18633
  var init_file_completion = () => {};
16364
18634
 
16365
18635
  // packages/gateway/src/unix-link.ts
16366
- import { lstat as lstat2, mkdir as mkdir4, unlink as unlink2 } from "fs/promises";
18636
+ import { lstat as lstat2, mkdir as mkdir4, unlink as unlink3 } from "fs/promises";
16367
18637
  import { connect, createServer } from "net";
16368
18638
  import { dirname as dirname7 } from "path";
16369
18639
  import { webSocketLink as webSocketLink2 } from "@earendil-works/chord";
@@ -16506,7 +18776,7 @@ function createUnixListener(options) {
16506
18776
  });
16507
18777
  if (active)
16508
18778
  throw new Error("Gateway already running at this socket");
16509
- await unlink2(options.path);
18779
+ await unlink3(options.path);
16510
18780
  } catch (error) {
16511
18781
  if (error.code !== "ENOENT")
16512
18782
  throw error;
@@ -16536,7 +18806,7 @@ function createUnixListener(options) {
16536
18806
  await new Promise((resolve) => previous.close(() => resolve()));
16537
18807
  if (bound) {
16538
18808
  bound = false;
16539
- await unlink2(options.path).catch(() => {});
18809
+ await unlink3(options.path).catch(() => {});
16540
18810
  }
16541
18811
  }
16542
18812
  };
@@ -17004,7 +19274,7 @@ var init_subagent_host = __esm(() => {
17004
19274
  });
17005
19275
 
17006
19276
  // packages/gateway/src/session-host.ts
17007
- import { open as open2 } from "fs/promises";
19277
+ import { open as open3 } from "fs/promises";
17008
19278
  import { basename as basename5, extname } from "path";
17009
19279
  import {
17010
19280
  ChordError as ChordError2,
@@ -17185,7 +19455,7 @@ function serveSessions(host, runtime, context) {
17185
19455
  const model = runtime.listModels().find((m) => m.provider === agent.model?.provider && m.modelId === agent.model?.modelId);
17186
19456
  if (!model?.input.includes("image"))
17187
19457
  throw new Error("Current model does not support images");
17188
- const handle = await open2(target, "r");
19458
+ const handle = await open3(target, "r");
17189
19459
  let id;
17190
19460
  try {
17191
19461
  const info = await handle.stat();
@@ -17421,7 +19691,7 @@ var require2, _a, Worker, isMarkedAsUntransferable, u8, u16, i32, fleb, fdeb, cl
17421
19691
  }
17422
19692
  }
17423
19693
  return { b, r };
17424
- }, _a, fl, revfl, _b, fd, revfd, rev, x, i, hMap = function(cd, mb, r) {
19694
+ }, _a, fl, revfl, _b, fd, revfd, rev, x2, i, hMap = function(cd, mb, r) {
17425
19695
  var s = cd.length;
17426
19696
  var i = 0;
17427
19697
  var l = new u16(mb);
@@ -17625,7 +19895,7 @@ var require2, _a, Worker, isMarkedAsUntransferable, u8, u16, i32, fleb, fdeb, cl
17625
19895
  final = 1, st.m = lbt, st.d = dm, st.n = dbt;
17626
19896
  } while (!final);
17627
19897
  return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
17628
- }, et, b2 = function(d, b) {
19898
+ }, et2, b2 = function(d, b) {
17629
19899
  return d[b] | d[b + 1] << 8;
17630
19900
  }, b4 = function(d, b) {
17631
19901
  return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
@@ -17691,10 +19961,10 @@ var init_esm = __esm(() => {
17691
19961
  revfd = _b.r;
17692
19962
  rev = new u16(32768);
17693
19963
  for (i = 0;i < 32768; ++i) {
17694
- x = (i & 43690) >> 1 | (i & 21845) << 1;
17695
- x = (x & 52428) >> 2 | (x & 13107) << 2;
17696
- x = (x & 61680) >> 4 | (x & 3855) << 4;
17697
- rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
19964
+ x2 = (i & 43690) >> 1 | (i & 21845) << 1;
19965
+ x2 = (x2 & 52428) >> 2 | (x2 & 13107) << 2;
19966
+ x2 = (x2 & 61680) >> 4 | (x2 & 3855) << 4;
19967
+ rev[i] = ((x2 & 65280) >> 8 | (x2 & 255) << 8) >> 1;
17698
19968
  }
17699
19969
  flt = new u8(288);
17700
19970
  for (i = 0;i < 144; ++i)
@@ -17726,10 +19996,10 @@ var init_esm = __esm(() => {
17726
19996
  "stream finishing",
17727
19997
  "invalid zip data"
17728
19998
  ];
17729
- et = /* @__PURE__ */ new u8(0);
19999
+ et2 = /* @__PURE__ */ new u8(0);
17730
20000
  td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder;
17731
20001
  try {
17732
- td.decode(et, { stream: true });
20002
+ td.decode(et2, { stream: true });
17733
20003
  tds = 1;
17734
20004
  } catch (e) {}
17735
20005
  });
@@ -17737,10 +20007,10 @@ var init_esm = __esm(() => {
17737
20007
  // packages/gateway/src/skill-market.ts
17738
20008
  import { createHash, randomUUID as randomUUID2 } from "crypto";
17739
20009
  import { mkdir as mkdir5, readdir as readdir2, rename as rename3, rm as rm4, stat as stat3, writeFile as writeFile4 } from "fs/promises";
17740
- import { homedir as homedir6 } from "os";
20010
+ import { homedir as homedir7 } from "os";
17741
20011
  import { dirname as dirname8, join as join9 } from "path";
17742
20012
  function createSkillMarketClient(options) {
17743
- const home = options.home ?? homedir6();
20013
+ const home = options.home ?? homedir7();
17744
20014
  const fetchImpl = options.fetchImpl ?? fetch;
17745
20015
  const now = options.now ?? Date.now;
17746
20016
  let base;
@@ -18468,7 +20738,7 @@ var init_src2 = __esm(() => {
18468
20738
  });
18469
20739
 
18470
20740
  // packages/tui/src/gateway.ts
18471
- import { spawn as spawn2 } from "child_process";
20741
+ import { spawn as spawn3 } from "child_process";
18472
20742
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
18473
20743
  import { basename as basename7, dirname as dirname11, join as join12 } from "path";
18474
20744
  async function connectToGateway(options = {}) {
@@ -18509,7 +20779,7 @@ async function connectToGateway(options = {}) {
18509
20779
  }
18510
20780
  async function spawnAndConnect(plan) {
18511
20781
  const command = gatewayCommand(gatewayArgs(plan));
18512
- const child = spawn2(command.binary, command.args, { stdio: ["ignore", "pipe", "pipe"] });
20782
+ const child = spawn3(command.binary, command.args, { stdio: ["ignore", "pipe", "pipe"] });
18513
20783
  const outputTail = captureOutput(child);
18514
20784
  let spawnError;
18515
20785
  child.on("error", (error) => {
@@ -18683,6 +20953,7 @@ function helpLines(platform = process.platform) {
18683
20953
  ["Alt+Enter", "Queue while running"],
18684
20954
  ["Esc", "Stop a running task or blocking compaction"],
18685
20955
  ["Esc Esc", "Clear draft when idle (press twice quickly)"],
20956
+ ["Up / Down", "Browse previous inputs in this session"],
18686
20957
  ["Ctrl+C", "Stop while running; exit when idle"],
18687
20958
  ["Ctrl+S", "Open sessions"],
18688
20959
  [platform === "win32" ? "Alt+V" : "Ctrl+V", "Paste clipboard image or text"],
@@ -18791,8 +21062,8 @@ var init_help_ui = __esm(() => {
18791
21062
  // packages/tui/src/image-input.ts
18792
21063
  import { execFile as execFile2 } from "child_process";
18793
21064
  import { readFile as readFile8, stat as stat5 } from "fs/promises";
18794
- import { homedir as homedir7 } from "os";
18795
- import { basename as basename8, resolve as resolve4 } from "path";
21065
+ import { homedir as homedir8 } from "os";
21066
+ import { basename as basename8, resolve as resolve5 } from "path";
18796
21067
  import { promisify as promisify2 } from "util";
18797
21068
  import { isKeyRelease as isKeyRelease4, isKeyRepeat as isKeyRepeat2, matchesKey as matchesKey7 } from "@earendil-works/pi-tui";
18798
21069
  function imagePaths(text, platform = process.platform) {
@@ -18826,7 +21097,7 @@ function imagePaths(text, platform = process.platform) {
18826
21097
  return paths.length && paths.every((p) => /\.(png|jpe?g|webp)$/i.test(p)) ? paths : null;
18827
21098
  }
18828
21099
  async function readImageFile(path, cwd) {
18829
- const full = resolve4(cwd, path.startsWith("~/") ? homedir7() + path.slice(1) : path);
21100
+ const full = resolve5(cwd, path.startsWith("~/") ? homedir8() + path.slice(1) : path);
18830
21101
  const info = await stat5(full);
18831
21102
  if (!info.isFile() || info.size > 20 * 1024 * 1024)
18832
21103
  throw new Error("Image must be a file no larger than 20 MiB");
@@ -19574,20 +21845,6 @@ var init_version_ui = __esm(() => {
19574
21845
  init_application_version();
19575
21846
  });
19576
21847
 
19577
- // packages/core/src/session-display.ts
19578
- function relativeTime(at, now, language = "en") {
19579
- const minutes = Math.floor(Math.max(0, now - at) / 60000);
19580
- if (minutes < 1)
19581
- return language === "zh" ? "\u521A\u521A" : "now";
19582
- const hours = Math.floor(minutes / 60), days = Math.floor(hours / 24);
19583
- if (days >= 30)
19584
- return new Date(at).toLocaleDateString(language === "zh" ? "zh-CN" : "en-GB");
19585
- const value = days || hours || minutes;
19586
- const unit = days ? ["\u5929", "d"] : hours ? ["\u5C0F\u65F6", "h"] : ["\u5206\u949F", "m"];
19587
- return language === "zh" ? `${value} ${unit[0]}\u524D` : `${value}${unit[1]}`;
19588
- }
19589
- var sessionName = (session, empty = "New session") => session.title || session.firstPromptPreview || empty, messageTime = (session) => session.lastMessageAt ?? session.createdAt, byMessage = (a, b) => messageTime(b) - messageTime(a) || Number(b.id) - Number(a.id), byVisited = (a, b) => b.lastUsedAt - a.lastUsedAt || Number(b.id) - Number(a.id);
19590
-
19591
21848
  // packages/tui/src/workspace.ts
19592
21849
  function workspaceSessions(sessions, cwd) {
19593
21850
  return sessions.filter((s) => s.workspaceRoot === cwd).sort(byMessage);
@@ -19639,6 +21896,7 @@ class NekoTuiApp {
19639
21896
  #noticeTimer;
19640
21897
  #compactionTimer;
19641
21898
  #editor;
21899
+ #historyItems;
19642
21900
  #footer = new StatusFooter;
19643
21901
  #welcome = new WelcomeScreen;
19644
21902
  #welcomeAttached = false;
@@ -19977,6 +22235,14 @@ class NekoTuiApp {
19977
22235
  this.#manage(() => this.archiveSession());
19978
22236
  return;
19979
22237
  }
22238
+ if (trimmed === "/copy") {
22239
+ this.#copyLastAnswer();
22240
+ return;
22241
+ }
22242
+ if (trimmed === "/export" || trimmed.startsWith("/export ")) {
22243
+ this.#exportSession(trimmed.slice("/export".length));
22244
+ return;
22245
+ }
19980
22246
  const chat = this.#chat;
19981
22247
  if (chat === undefined)
19982
22248
  return;
@@ -20077,6 +22343,44 @@ class NekoTuiApp {
20077
22343
  this.#ui.requestRender();
20078
22344
  }
20079
22345
  }
22346
+ async#copyLastAnswer() {
22347
+ const outcome = await copyLastAnswer(this.#lastView?.items ?? [], {
22348
+ osc52: (sequence) => this.#terminal.write(sequence)
22349
+ });
22350
+ this.addNotice(outcome.message, outcome.level);
22351
+ }
22352
+ async#exportSession(argumentText) {
22353
+ const view = this.#lastView;
22354
+ const chat = this.#chat;
22355
+ const sessionId = this.#sessionId;
22356
+ if (view === undefined || chat === undefined) {
22357
+ this.addNotice("No session is open.", "warning");
22358
+ return;
22359
+ }
22360
+ let args;
22361
+ try {
22362
+ args = parseExportArgs(argumentText);
22363
+ } catch (error) {
22364
+ this.addNotice(messageOf(error), "warning", { wrap: true });
22365
+ return;
22366
+ }
22367
+ const summary = this.#gateway.client.directory.state.value?.sessions.find((s) => s.id === sessionId);
22368
+ const title = summary ? sessionName(summary, "") : "";
22369
+ this.addNotice("Exporting...");
22370
+ try {
22371
+ const { path, skippedImages } = await exportToFile({
22372
+ ...args,
22373
+ cwd: this.#options.cwd ?? process.cwd(),
22374
+ source: { sessionId, title, model: view.model, cwd: view.cwd, exportedAt: new Date, items: view.items },
22375
+ loadImage: (image) => downloadImage((offset) => chat.getImage({ entryId: image.entryId, contentIndex: image.contentIndex, offset }))
22376
+ });
22377
+ const other = sessionId !== this.#sessionId ? ` (session ${title || sessionId})` : "";
22378
+ const skipped = skippedImages > 0 ? `; ${skippedImages} image(s) not embedded` : "";
22379
+ this.addNotice(`Exported${other} to ${path}${skipped}`, "info", { wrap: true, ttlMs: 20000 });
22380
+ } catch (error) {
22381
+ this.addNotice(`Export failed: ${messageOf(error)}`, "error", { wrap: true, ttlMs: 20000 });
22382
+ }
22383
+ }
20080
22384
  abort() {
20081
22385
  const chat = this.#chat;
20082
22386
  if (chat === undefined)
@@ -20107,6 +22411,8 @@ class NekoTuiApp {
20107
22411
  this.#sessionId = id;
20108
22412
  this.#refreshSkills(handle);
20109
22413
  this.#editor.setText(this.#texts.get(id) ?? "");
22414
+ this.#editor.setHistory([]);
22415
+ this.#historyItems = undefined;
20110
22416
  this.#resetTranscript();
20111
22417
  const view = handle.view;
20112
22418
  if (view.value !== undefined)
@@ -20302,14 +22608,15 @@ class NekoTuiApp {
20302
22608
  this.#login.close();
20303
22609
  this.#ui.setFocus(this.#editor);
20304
22610
  }
20305
- addNotice(text, level = "info") {
22611
+ addNotice(text, level = "info", options = {}) {
20306
22612
  clearTimeout(this.#noticeTimer);
20307
22613
  this.#noticeTimer = setTimeout(() => {
20308
22614
  this.#notices.clear();
20309
22615
  this.#ui.requestRender();
20310
- }, 5000);
22616
+ }, options.ttlMs ?? 5000);
20311
22617
  this.#notices.clear();
20312
- this.#notices.addChild(new ThemedTruncatedText(() => formatNotice(text, level), 1, 0));
22618
+ const content = () => formatNotice(text, level);
22619
+ this.#notices.addChild(options.wrap ? new ThemedWrappedText(content) : new ThemedTruncatedText(content, 1, 0));
20313
22620
  this.#ui.requestRender();
20314
22621
  }
20315
22622
  scheduleApply() {
@@ -20333,6 +22640,10 @@ class NekoTuiApp {
20333
22640
  }
20334
22641
  applyView(view) {
20335
22642
  this.#lastView = view;
22643
+ if (this.#historyItems !== view.items) {
22644
+ this.#historyItems = view.items;
22645
+ this.#editor.setHistory(promptHistory(view.items));
22646
+ }
20336
22647
  if (this.#chat)
20337
22648
  this.#approval.update(view.subagents ?? []);
20338
22649
  else
@@ -20462,7 +22773,11 @@ class NekoTuiApp {
20462
22773
  summary: item.summary,
20463
22774
  detail: item.detail,
20464
22775
  phase: item.phase,
20465
- output: item.output
22776
+ output: item.output,
22777
+ diff: item.diff,
22778
+ diffAdded: item.diffAdded,
22779
+ diffRemoved: item.diffRemoved,
22780
+ diffTruncated: item.diffTruncated
20466
22781
  });
20467
22782
  component.sync(item);
20468
22783
  this.#items.set(item.key, { kind: "tool", component });
@@ -20615,7 +22930,11 @@ function streamingCardState(call) {
20615
22930
  output: call.output,
20616
22931
  result: null,
20617
22932
  durationMs: null,
20618
- note: null
22933
+ note: null,
22934
+ diff: call.diff,
22935
+ diffAdded: call.diffAdded,
22936
+ diffRemoved: call.diffRemoved,
22937
+ diffTruncated: call.diffTruncated
20619
22938
  };
20620
22939
  }
20621
22940
  function messageOf(error) {
@@ -20661,7 +22980,9 @@ var EXIT_COMMANDS, SESSIONS_COMMANDS, NEW_SESSION_VALUE = "__new__";
20661
22980
  var init_tui = __esm(() => {
20662
22981
  init_src();
20663
22982
  init_application_updates();
22983
+ init_input_history();
20664
22984
  init_approval_dock();
22985
+ init_clipboard_write();
20665
22986
  init_assistant_message();
20666
22987
  init_editor();
20667
22988
  init_footer();
@@ -20673,6 +22994,7 @@ var init_tui = __esm(() => {
20673
22994
  init_tool_execution();
20674
22995
  init_user_message();
20675
22996
  init_welcome();
22997
+ init_export_command();
20676
22998
  init_file_completion();
20677
22999
  init_gateway2();
20678
23000
  init_help_ui();
@@ -20798,7 +23120,7 @@ function openBrowser(url) {
20798
23120
  var init_open_browser = () => {};
20799
23121
 
20800
23122
  // packages/web/src/gateway-spawn.ts
20801
- import { spawn as spawn3 } from "child_process";
23123
+ import { spawn as spawn4 } from "child_process";
20802
23124
  import { randomUUID as randomUUID5 } from "crypto";
20803
23125
  import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
20804
23126
  import { dirname as dirname12, join as join13 } from "path";
@@ -20900,7 +23222,7 @@ function spawnGatewayProcess(options, socketPath, serverId) {
20900
23222
  ...options.model !== undefined ? ["--model", `${options.model.provider}/${options.model.modelId}`] : []
20901
23223
  ];
20902
23224
  const command = gatewayCommand(args);
20903
- return spawn3(command.binary, command.args, { env: process.env, stdio: ["ignore", "pipe", "pipe"] });
23225
+ return spawn4(command.binary, command.args, { env: process.env, stdio: ["ignore", "pipe", "pipe"] });
20904
23226
  }
20905
23227
  function pipeChildLogs(child, onLog) {
20906
23228
  if (onLog === undefined)
@@ -20990,10 +23312,10 @@ var init_gateway_spawn = __esm(() => {
20990
23312
  import { createReadStream } from "fs";
20991
23313
  import { stat as stat6 } from "fs/promises";
20992
23314
  import { createServer as createServer2 } from "http";
20993
- import { dirname as dirname13, extname as extname2, resolve as resolve5, sep as sep2 } from "path";
23315
+ import { dirname as dirname13, extname as extname2, resolve as resolve6, sep as sep2 } from "path";
20994
23316
  import { fileURLToPath as fileURLToPath5 } from "url";
20995
23317
  async function startWebServer(options = {}) {
20996
- const staticDir = resolve5(options.staticDir ?? DEFAULT_STATIC_DIR);
23318
+ const staticDir = resolve6(options.staticDir ?? DEFAULT_STATIC_DIR);
20997
23319
  const workspaceRoot = normalizeWorkspace(options.gateway?.cwd ?? process.cwd());
20998
23320
  const gateway = await ensureNekoGateway({
20999
23321
  ...options.gateway ?? {},
@@ -21072,7 +23394,7 @@ async function handleHttp(request, response, info) {
21072
23394
  }
21073
23395
  async function serveStatic(pathname, method, response, staticDir) {
21074
23396
  const cleanPath = decodeURIComponent(pathname);
21075
- const candidate = resolve5(staticDir, `.${cleanPath}`);
23397
+ const candidate = resolve6(staticDir, `.${cleanPath}`);
21076
23398
  if (candidate !== staticDir && !candidate.startsWith(staticDir + sep2)) {
21077
23399
  response.writeHead(403);
21078
23400
  response.end();
@@ -21083,13 +23405,13 @@ async function serveStatic(pathname, method, response, staticDir) {
21083
23405
  return;
21084
23406
  });
21085
23407
  if (stats?.isDirectory()) {
21086
- file = resolve5(file, "index.html");
23408
+ file = resolve6(file, "index.html");
21087
23409
  stats = await stat6(file).catch(() => {
21088
23410
  return;
21089
23411
  });
21090
23412
  }
21091
23413
  if (stats === undefined && extname2(candidate) === "") {
21092
- file = resolve5(staticDir, "index.html");
23414
+ file = resolve6(staticDir, "index.html");
21093
23415
  stats = await stat6(file).catch(() => {
21094
23416
  return;
21095
23417
  });