@ridit/lens 0.1.7 → 0.1.8

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/index.mjs CHANGED
@@ -44359,6 +44359,14 @@ var build_default = Spinner;
44359
44359
 
44360
44360
  // src/colors.ts
44361
44361
  var ACCENT = "#DA7758";
44362
+ var TOKEN_KEYWORD = "#B385C9";
44363
+ var TOKEN_STRING = "#85C98A";
44364
+ var TOKEN_NUMBER = "#E8C170";
44365
+ var TOKEN_PROPERTY = "#79C5D4";
44366
+ var TOKEN_ENTITY = "#7AABDB";
44367
+ var TOKEN_TEXT = "#E8E8E8";
44368
+ var TOKEN_MUTED = "#888888";
44369
+ var TOKEN_COMMENT = "#777777";
44362
44370
 
44363
44371
  // src/utils/thinking.tsx
44364
44372
  var import_react30 = __toESM(require_react(), 1);
@@ -48707,10 +48715,10 @@ More content."}
48707
48715
  ### 11. search — search the internet for anything you are unsure about
48708
48716
  <search>how to use React useEffect cleanup function</search>
48709
48717
 
48710
- ### 11. clone — clone a GitHub repo so you can explore and discuss it
48718
+ ### 12. clone — clone a GitHub repo so you can explore and discuss it
48711
48719
  <clone>https://github.com/owner/repo</clone>
48712
48720
 
48713
- ### 12. changes — propose code edits (shown as a diff for user approval)
48721
+ ### 13. changes — propose code edits (shown as a diff for user approval)
48714
48722
  <changes>
48715
48723
  {"summary": "what changed and why", "patches": [{"path": "src/foo.ts", "content": "COMPLETE file content", "isNew": false}]}
48716
48724
  </changes>
@@ -48729,16 +48737,19 @@ More content."}
48729
48737
  10. shell is ONLY for running code, installing packages, building, testing — not for filesystem inspection
48730
48738
  11. write-file content field must be the COMPLETE file content, never empty or placeholder
48731
48739
  12. After a write-file succeeds, do NOT repeat it — trust the result and move on
48732
- 13. After a write-file succeeds, use read-file to verify the content before telling the user it is done
48740
+ 13. After a write-file succeeds, tell the user it is done immediately do NOT auto-read the file back to verify
48733
48741
  14. NEVER apologize and redo a tool call you already made — if write-file or shell ran and returned a result, it worked, do not run it again
48734
48742
  15. NEVER say "I made a mistake" and repeat the same tool — one attempt is enough, trust the output
48735
48743
  16. NEVER second-guess yourself mid-response — commit to your answer
48736
48744
  17. If a read-folder or read-file returns "not found", accept it and move on — do NOT retry the same path
48737
48745
  18. If you have already retrieved a result for a path in this conversation, do NOT request it again — use the result you already have
48738
- 17. Every shell command runs from the repo root — \`cd\` has NO persistent effect. NEVER use \`cd\` alone. Use full paths or combine with && e.g. \`cd list && bun run index.ts\`
48739
- 18. write-file paths are relative to the repo root — if creating files in a subfolder write the full relative path e.g. \`list/src/index.tsx\` NOT \`src/index.tsx\`
48740
- 19. When scaffolding a new project in a subfolder, ALL write-file paths must start with that subfolder name e.g. \`list/package.json\`, \`list/src/index.tsx\`
48741
- 20. For JSX/TSX files always use \`.tsx\` extension and include \`/** @jsxImportSource react */\` or ensure tsconfig has jsx set — bun needs this to parse JSX
48746
+ 19. Every shell command runs from the repo root — \`cd\` has NO persistent effect. NEVER use \`cd\` alone. Use full paths or combine with && e.g. \`cd list && bun run index.ts\`
48747
+ 20. write-file paths are relative to the repo root — if creating files in a subfolder write the full relative path e.g. \`list/src/index.tsx\` NOT \`src/index.tsx\`
48748
+ 21. When scaffolding a new project in a subfolder, ALL write-file paths must start with that subfolder name e.g. \`list/package.json\`, \`list/src/index.tsx\`
48749
+ 22. For JSX/TSX files always use \`.tsx\` extension and include \`/** @jsxImportSource react */\` or ensure tsconfig has jsx set — bun needs this to parse JSX
48750
+ 23. When explaining how to use a tool in text, use [tag] bracket notation or a fenced code block — NEVER emit a real XML tool tag as part of an explanation or example
48751
+ 24. NEVER chain tool calls unless the user's request explicitly requires multiple steps
48752
+ 25. NEVER read files, list folders, or run tools that were not asked for in the current user message
48742
48753
 
48743
48754
  ## CRITICAL: READ BEFORE YOU WRITE
48744
48755
 
@@ -48952,6 +48963,22 @@ Please continue your response based on this output.`
48952
48963
  role: "assistant",
48953
48964
  content: "`useInput` is used in `src/components/chat/ChatRunner.tsx` — imported on line 5 and called on line 210."
48954
48965
  },
48966
+ {
48967
+ role: "user",
48968
+ content: "show me how to use the read-file tool"
48969
+ },
48970
+ {
48971
+ role: "assistant",
48972
+ content: "To read a file, emit the tag alone in your response — nothing else on that turn:\n\n```text\n[read-file]src/components/Header.tsx[/read-file]\n```\n\nThe result comes back as the next user message and you can then analyze it."
48973
+ },
48974
+ {
48975
+ role: "user",
48976
+ content: "show me an example of the shell tool"
48977
+ },
48978
+ {
48979
+ role: "assistant",
48980
+ content: "To run a shell command, emit only the tag:\n\n```text\n[shell]node -v[/shell]\n```\n\nThe stdout/stderr is returned and you can read it in the next turn."
48981
+ },
48955
48982
  {
48956
48983
  role: "user",
48957
48984
  content: "read src folder"
@@ -49187,21 +49214,29 @@ Please continue your response based on this output.`
49187
49214
  },
49188
49215
  {
49189
49216
  role: "assistant",
49190
- content: "<read-file>ts-info.json</read-file>"
49217
+ content: "Done — `ts-info.json` has been saved."
49191
49218
  },
49192
49219
  {
49193
49220
  role: "user",
49194
- content: `Here is the output from read-file of ts-info.json:
49195
-
49196
- File: ts-info.json (1 lines)
49221
+ content: "write it to a file called hello.py"
49222
+ },
49223
+ {
49224
+ role: "assistant",
49225
+ content: `<write-file>
49226
+ {"path": "hello.py", "content": "# hello.py\\nprint('hello')"}
49227
+ </write-file>`
49228
+ },
49229
+ {
49230
+ role: "user",
49231
+ content: `Here is the output from write-file to hello.py:
49197
49232
 
49198
- {"name":"TypeScript","stars":100000}
49233
+ Written: /repo/hello.py (2 lines, 32 bytes)
49199
49234
 
49200
49235
  Please continue your response based on this output.`
49201
49236
  },
49202
49237
  {
49203
49238
  role: "assistant",
49204
- content: "Done — saved and verified `ts-info.json`. Data looks correct."
49239
+ content: "Done — `hello.py` has been written."
49205
49240
  },
49206
49241
  {
49207
49242
  role: "user",
@@ -49286,6 +49321,7 @@ Please continue your response based on this output.`
49286
49321
  }
49287
49322
  ];
49288
49323
  function parseResponse(text) {
49324
+ const scanText = text.replace(/```[\s\S]*?```/g, (m) => " ".repeat(m.length));
49289
49325
  const candidates = [];
49290
49326
  const patterns = [
49291
49327
  { kind: "fetch", re: /<fetch>([\s\S]*?)<\/fetch>/g },
@@ -49314,16 +49350,25 @@ function parseResponse(text) {
49314
49350
  ];
49315
49351
  for (const { kind: kind2, re } of patterns) {
49316
49352
  re.lastIndex = 0;
49317
- const m = re.exec(text);
49318
- if (m)
49319
- candidates.push({ index: m.index, kind: kind2, match: m });
49353
+ const m = re.exec(scanText);
49354
+ if (m) {
49355
+ const originalRe = new RegExp(re.source, re.flags.replace("g", ""));
49356
+ const originalMatch = originalRe.exec(text.slice(m.index));
49357
+ if (originalMatch) {
49358
+ const fakeMatch = Object.assign([
49359
+ text.slice(m.index, m.index + originalMatch[0].length),
49360
+ originalMatch[1]
49361
+ ], { index: m.index, input: text, groups: undefined });
49362
+ candidates.push({ index: m.index, kind: kind2, match: fakeMatch });
49363
+ }
49364
+ }
49320
49365
  }
49321
49366
  if (candidates.length === 0)
49322
49367
  return { kind: "text", content: text.trim() };
49323
49368
  candidates.sort((a, b) => a.index - b.index);
49324
49369
  const { kind, match } = candidates[0];
49325
49370
  const before2 = text.slice(0, match.index).replace(/<(fetch|shell|read-file|read-folder|write-file|search|clone|changes)[^>]*>[\s\S]*?<\/\1>/g, "").trim();
49326
- const body = match[1].trim();
49371
+ const body = (match[1] ?? "").trim();
49327
49372
  if (kind === "changes") {
49328
49373
  try {
49329
49374
  const parsed = JSON.parse(body);
@@ -49426,7 +49471,7 @@ Please continue your response based on this output.`
49426
49471
  return { role: m.role, content: m.content };
49427
49472
  });
49428
49473
  }
49429
- async function callChat(provider, systemPrompt, messages) {
49474
+ async function callChat(provider, systemPrompt, messages, abortSignal) {
49430
49475
  const apiMessages = [...FEW_SHOT_MESSAGES, ...buildApiMessages(messages)];
49431
49476
  let url;
49432
49477
  let headers;
@@ -49459,6 +49504,7 @@ async function callChat(provider, systemPrompt, messages) {
49459
49504
  }
49460
49505
  const controller = new AbortController;
49461
49506
  const timer = setTimeout(() => controller.abort(), 60000);
49507
+ abortSignal?.addEventListener("abort", () => controller.abort());
49462
49508
  const res = await fetch(url, {
49463
49509
  method: "POST",
49464
49510
  headers,
@@ -50010,7 +50056,6 @@ for line in raw.split("\\n"):
50010
50056
  elif s == "":
50011
50057
  story.append(Spacer(1, 6))
50012
50058
  else:
50013
- # handle **bold** inline
50014
50059
  import re
50015
50060
  s = re.sub(r"\\*\\*(.+?)\\*\\*", r"<b>\\1</b>", s)
50016
50061
  s = re.sub(r"\\*(.+?)\\*", r"<i>\\1</i>", s)
@@ -50034,113 +50079,1014 @@ print("OK")
50034
50079
  }
50035
50080
  }
50036
50081
 
50082
+ // node_modules/sugar-high/lib/index.js
50083
+ var JSXBrackets = new Set(["<", ">", "{", "}", "[", "]"]);
50084
+ var Keywords_Js = new Set([
50085
+ "for",
50086
+ "do",
50087
+ "while",
50088
+ "if",
50089
+ "else",
50090
+ "return",
50091
+ "function",
50092
+ "var",
50093
+ "let",
50094
+ "const",
50095
+ "true",
50096
+ "false",
50097
+ "undefined",
50098
+ "this",
50099
+ "new",
50100
+ "delete",
50101
+ "typeof",
50102
+ "in",
50103
+ "instanceof",
50104
+ "void",
50105
+ "break",
50106
+ "continue",
50107
+ "switch",
50108
+ "case",
50109
+ "default",
50110
+ "throw",
50111
+ "try",
50112
+ "catch",
50113
+ "finally",
50114
+ "debugger",
50115
+ "with",
50116
+ "yield",
50117
+ "async",
50118
+ "await",
50119
+ "class",
50120
+ "extends",
50121
+ "super",
50122
+ "import",
50123
+ "export",
50124
+ "from",
50125
+ "static"
50126
+ ]);
50127
+ var Signs = new Set([
50128
+ "+",
50129
+ "-",
50130
+ "*",
50131
+ "/",
50132
+ "%",
50133
+ "=",
50134
+ "!",
50135
+ "&",
50136
+ "|",
50137
+ "^",
50138
+ "~",
50139
+ "!",
50140
+ "?",
50141
+ ":",
50142
+ ".",
50143
+ ",",
50144
+ ";",
50145
+ `'`,
50146
+ '"',
50147
+ ".",
50148
+ "(",
50149
+ ")",
50150
+ "[",
50151
+ "]",
50152
+ "#",
50153
+ "@",
50154
+ "\\",
50155
+ ...JSXBrackets
50156
+ ]);
50157
+ var DefaultOptions = {
50158
+ keywords: Keywords_Js,
50159
+ onCommentStart: isCommentStart_Js,
50160
+ onCommentEnd: isCommentEnd_Js
50161
+ };
50162
+ var TokenTypes = [
50163
+ "identifier",
50164
+ "keyword",
50165
+ "string",
50166
+ "class",
50167
+ "property",
50168
+ "entity",
50169
+ "jsxliterals",
50170
+ "sign",
50171
+ "comment",
50172
+ "break",
50173
+ "space"
50174
+ ];
50175
+ var [
50176
+ T_IDENTIFIER,
50177
+ T_KEYWORD,
50178
+ T_STRING,
50179
+ T_CLS_NUMBER,
50180
+ T_PROPERTY,
50181
+ T_ENTITY,
50182
+ T_JSX_LITERALS,
50183
+ T_SIGN,
50184
+ T_COMMENT,
50185
+ T_BREAK,
50186
+ T_SPACE
50187
+ ] = TokenTypes.map((_, i) => i);
50188
+ function isSpaces(str) {
50189
+ return /^[^\S\r\n]+$/g.test(str);
50190
+ }
50191
+ function isSign(ch) {
50192
+ return Signs.has(ch);
50193
+ }
50194
+ function isWord(chr) {
50195
+ return /^[\w_]+$/.test(chr) || hasUnicode(chr);
50196
+ }
50197
+ function isCls(str) {
50198
+ const chr0 = str[0];
50199
+ return isWord(chr0) && chr0 === chr0.toUpperCase() || str === "null";
50200
+ }
50201
+ function hasUnicode(s) {
50202
+ return /[^\u0000-\u007f]/.test(s);
50203
+ }
50204
+ function isAlpha(chr) {
50205
+ return /^[a-zA-Z]$/.test(chr);
50206
+ }
50207
+ function isIdentifierChar(chr) {
50208
+ return isAlpha(chr) || hasUnicode(chr);
50209
+ }
50210
+ function isIdentifier(str) {
50211
+ return isIdentifierChar(str[0]) && (str.length === 1 || isWord(str.slice(1)));
50212
+ }
50213
+ function isStrTemplateChr(chr) {
50214
+ return chr === "`";
50215
+ }
50216
+ function isSingleQuotes(chr) {
50217
+ return chr === '"' || chr === "'";
50218
+ }
50219
+ function isStringQuotation(chr) {
50220
+ return isSingleQuotes(chr) || isStrTemplateChr(chr);
50221
+ }
50222
+ function isCommentStart_Js(curr, next) {
50223
+ const str = curr + next;
50224
+ if (str === "/*")
50225
+ return 2;
50226
+ return str === "//" ? 1 : 0;
50227
+ }
50228
+ function isCommentEnd_Js(prev, curr) {
50229
+ return prev + curr === "*/" ? 2 : curr === `
50230
+ ` ? 1 : 0;
50231
+ }
50232
+ function isRegexStart(str) {
50233
+ return str[0] === "/" && !isCommentStart_Js(str[0], str[1]);
50234
+ }
50235
+ function tokenize3(code, options) {
50236
+ const {
50237
+ keywords,
50238
+ onCommentStart,
50239
+ onCommentEnd
50240
+ } = { ...DefaultOptions, ...options };
50241
+ let current = "";
50242
+ let type = -1;
50243
+ let last2 = [-1, ""];
50244
+ let beforeLast = [-2, ""];
50245
+ const tokens = [];
50246
+ let __jsxEnter = false;
50247
+ let __jsxTag = 0;
50248
+ let __jsxExpr = false;
50249
+ let __jsxStack = 0;
50250
+ const __jsxChild = () => __jsxEnter && !__jsxExpr && !__jsxTag;
50251
+ const inJsxTag = () => __jsxTag && !__jsxChild();
50252
+ const inJsxLiterals = () => !__jsxTag && __jsxChild() && !__jsxExpr && __jsxStack > 0;
50253
+ let __strQuote = null;
50254
+ let __regexQuoteStart = false;
50255
+ let __strTemplateExprStack = 0;
50256
+ let __strTemplateQuoteStack = 0;
50257
+ const inStringQuotes = () => __strQuote !== null;
50258
+ const inRegexQuotes = () => __regexQuoteStart;
50259
+ const inStrTemplateLiterals = () => __strTemplateQuoteStack > __strTemplateExprStack;
50260
+ const inStrTemplateExpr = () => __strTemplateQuoteStack > 0 && __strTemplateQuoteStack === __strTemplateExprStack;
50261
+ const inStringContent = () => inStringQuotes() || inStrTemplateLiterals();
50262
+ function classify(token) {
50263
+ const isLineBreak = token === `
50264
+ `;
50265
+ if (inJsxTag()) {
50266
+ if (inStringQuotes()) {
50267
+ return T_STRING;
50268
+ }
50269
+ const [, lastToken] = last2;
50270
+ if (isIdentifier(token)) {
50271
+ if (lastToken === "<" || lastToken === "</")
50272
+ return T_ENTITY;
50273
+ }
50274
+ }
50275
+ const isJsxLiterals = inJsxLiterals();
50276
+ if (isJsxLiterals)
50277
+ return T_JSX_LITERALS;
50278
+ if (inStringQuotes() || inStrTemplateLiterals()) {
50279
+ return T_STRING;
50280
+ } else if (keywords.has(token)) {
50281
+ return last2[1] === "." ? T_IDENTIFIER : T_KEYWORD;
50282
+ } else if (isLineBreak) {
50283
+ return T_BREAK;
50284
+ } else if (isSpaces(token)) {
50285
+ return T_SPACE;
50286
+ } else if (token.split("").every(isSign)) {
50287
+ return T_SIGN;
50288
+ } else if (isCls(token)) {
50289
+ return inJsxTag() ? T_IDENTIFIER : T_CLS_NUMBER;
50290
+ } else {
50291
+ if (isIdentifier(token)) {
50292
+ const isLastPropDot = last2[1] === "." && isIdentifier(beforeLast[1]);
50293
+ if (!inStringContent() && !isLastPropDot)
50294
+ return T_IDENTIFIER;
50295
+ if (isLastPropDot)
50296
+ return T_PROPERTY;
50297
+ }
50298
+ return T_STRING;
50299
+ }
50300
+ }
50301
+ const append = (type_, token_) => {
50302
+ if (token_) {
50303
+ current = token_;
50304
+ }
50305
+ if (current) {
50306
+ type = type_ || classify(current);
50307
+ const pair = [type, current];
50308
+ if (type !== T_SPACE && type !== T_BREAK) {
50309
+ beforeLast = last2;
50310
+ last2 = pair;
50311
+ }
50312
+ tokens.push(pair);
50313
+ }
50314
+ current = "";
50315
+ };
50316
+ for (let i = 0;i < code.length; i++) {
50317
+ const curr = code[i];
50318
+ const prev = code[i - 1];
50319
+ const next = code[i + 1];
50320
+ const p_c = prev + curr;
50321
+ const c_n = curr + next;
50322
+ if (isSingleQuotes(curr) && !inJsxLiterals() && !inStrTemplateLiterals()) {
50323
+ append();
50324
+ if (prev !== `\\`) {
50325
+ if (__strQuote && curr === __strQuote) {
50326
+ __strQuote = null;
50327
+ } else if (!__strQuote) {
50328
+ __strQuote = curr;
50329
+ }
50330
+ }
50331
+ append(T_STRING, curr);
50332
+ continue;
50333
+ }
50334
+ if (!inStrTemplateLiterals()) {
50335
+ if (prev !== "\\n" && isStrTemplateChr(curr)) {
50336
+ append();
50337
+ append(T_STRING, curr);
50338
+ __strTemplateQuoteStack++;
50339
+ continue;
50340
+ }
50341
+ }
50342
+ if (inStrTemplateLiterals()) {
50343
+ if (prev !== "\\n" && isStrTemplateChr(curr)) {
50344
+ if (__strTemplateQuoteStack > 0) {
50345
+ append();
50346
+ __strTemplateQuoteStack--;
50347
+ append(T_STRING, curr);
50348
+ continue;
50349
+ }
50350
+ }
50351
+ if (c_n === "${") {
50352
+ __strTemplateExprStack++;
50353
+ append(T_STRING);
50354
+ append(T_SIGN, c_n);
50355
+ i++;
50356
+ continue;
50357
+ }
50358
+ }
50359
+ if (inStrTemplateExpr() && curr === "}") {
50360
+ append();
50361
+ __strTemplateExprStack--;
50362
+ append(T_SIGN, curr);
50363
+ continue;
50364
+ }
50365
+ if (__jsxChild()) {
50366
+ if (curr === "{") {
50367
+ append();
50368
+ append(T_SIGN, curr);
50369
+ __jsxExpr = true;
50370
+ continue;
50371
+ }
50372
+ }
50373
+ if (__jsxEnter) {
50374
+ if (!__jsxTag && curr === "<") {
50375
+ append();
50376
+ if (next === "/") {
50377
+ __jsxTag = 2;
50378
+ current = c_n;
50379
+ i++;
50380
+ } else {
50381
+ __jsxTag = 1;
50382
+ current = curr;
50383
+ }
50384
+ append(T_SIGN);
50385
+ continue;
50386
+ }
50387
+ if (__jsxTag) {
50388
+ if (curr === ">" && !"/=".includes(prev)) {
50389
+ append();
50390
+ if (__jsxTag === 1) {
50391
+ __jsxTag = 0;
50392
+ __jsxStack++;
50393
+ } else {
50394
+ __jsxTag = 0;
50395
+ __jsxEnter = false;
50396
+ }
50397
+ append(T_SIGN, curr);
50398
+ continue;
50399
+ }
50400
+ if (c_n === "/>" || c_n === "</") {
50401
+ if (current !== "<" && current !== "/") {
50402
+ append();
50403
+ }
50404
+ if (c_n === "/>") {
50405
+ __jsxTag = 0;
50406
+ } else {
50407
+ __jsxStack--;
50408
+ }
50409
+ if (!__jsxStack)
50410
+ __jsxEnter = false;
50411
+ current = c_n;
50412
+ i++;
50413
+ append(T_SIGN);
50414
+ continue;
50415
+ }
50416
+ if (curr === "<") {
50417
+ append();
50418
+ current = curr;
50419
+ append(T_SIGN);
50420
+ continue;
50421
+ }
50422
+ if (next === "-" && !inStringContent() && !inJsxLiterals()) {
50423
+ if (current) {
50424
+ append(T_PROPERTY, current + curr + next);
50425
+ i++;
50426
+ continue;
50427
+ }
50428
+ }
50429
+ if (next === "=" && !inStringContent()) {
50430
+ if (!isSpaces(curr)) {
50431
+ if (isSpaces(current)) {
50432
+ append();
50433
+ }
50434
+ const prop = current + curr;
50435
+ if (isIdentifier(prop)) {
50436
+ append(T_PROPERTY, prop);
50437
+ continue;
50438
+ }
50439
+ }
50440
+ }
50441
+ }
50442
+ }
50443
+ if (!__jsxTag && (curr === "<" && isIdentifierChar(next) || c_n === "</")) {
50444
+ __jsxTag = next === "/" ? 2 : 1;
50445
+ if (curr === "<" && (next === "/" || isAlpha(next))) {
50446
+ if (!inStringContent() && !inJsxLiterals() && !inRegexQuotes()) {
50447
+ __jsxEnter = true;
50448
+ }
50449
+ }
50450
+ }
50451
+ const isQuotationChar = isStringQuotation(curr);
50452
+ const isStringTemplateLiterals = inStrTemplateLiterals();
50453
+ const isRegexChar = !__jsxEnter && isRegexStart(c_n);
50454
+ const isJsxLiterals = inJsxLiterals();
50455
+ if (isQuotationChar || isStringTemplateLiterals || isSingleQuotes(__strQuote)) {
50456
+ current += curr;
50457
+ } else if (isRegexChar) {
50458
+ append();
50459
+ const [lastType, lastToken] = last2;
50460
+ if (isRegexChar && lastType !== -1 && !(lastType === T_SIGN && lastToken !== ")" || lastType === T_COMMENT)) {
50461
+ current = curr;
50462
+ append();
50463
+ continue;
50464
+ }
50465
+ __regexQuoteStart = true;
50466
+ const start = i++;
50467
+ const isEof = () => i >= code.length;
50468
+ const isEol = () => isEof() || code[i] === `
50469
+ `;
50470
+ let foundClose = false;
50471
+ for (;!isEol(); i++) {
50472
+ if (code[i] === "/" && code[i - 1] !== "\\") {
50473
+ foundClose = true;
50474
+ while (start !== i && /^[a-z]$/.test(code[i + 1]) && !isEol()) {
50475
+ i++;
50476
+ }
50477
+ break;
50478
+ }
50479
+ }
50480
+ __regexQuoteStart = false;
50481
+ if (start !== i && foundClose) {
50482
+ current = code.slice(start, i + 1);
50483
+ append(T_STRING);
50484
+ } else {
50485
+ current = curr;
50486
+ append();
50487
+ i = start;
50488
+ }
50489
+ } else if (onCommentStart(curr, next)) {
50490
+ append();
50491
+ const start = i;
50492
+ const startCommentType = onCommentStart(curr, next);
50493
+ if (startCommentType) {
50494
+ for (;i < code.length; i++) {
50495
+ const endCommentType = onCommentEnd(code[i - 1], code[i]);
50496
+ if (endCommentType == startCommentType)
50497
+ break;
50498
+ }
50499
+ }
50500
+ current = code.slice(start, i + 1);
50501
+ append(T_COMMENT);
50502
+ } else if (curr === " " || curr === `
50503
+ `) {
50504
+ if (curr === " " && (isSpaces(current) || !current || isJsxLiterals)) {
50505
+ current += curr;
50506
+ if (next === "<") {
50507
+ append();
50508
+ }
50509
+ } else {
50510
+ append();
50511
+ current = curr;
50512
+ append();
50513
+ }
50514
+ } else {
50515
+ if (__jsxExpr && curr === "}") {
50516
+ append();
50517
+ current = curr;
50518
+ append();
50519
+ __jsxExpr = false;
50520
+ } else if (isJsxLiterals && !JSXBrackets.has(curr) || inStrTemplateLiterals() || (isWord(curr) === isWord(current[current.length - 1]) || __jsxChild()) && !Signs.has(curr)) {
50521
+ current += curr;
50522
+ } else {
50523
+ if (p_c === "</") {
50524
+ current = p_c;
50525
+ }
50526
+ append();
50527
+ if (p_c !== "</") {
50528
+ current = curr;
50529
+ }
50530
+ if (c_n === "</" || c_n === "/>") {
50531
+ current = c_n;
50532
+ append();
50533
+ i++;
50534
+ } else if (JSXBrackets.has(curr))
50535
+ append();
50536
+ }
50537
+ }
50538
+ }
50539
+ append();
50540
+ return tokens;
50541
+ }
50542
+ var SugarHigh = {
50543
+ TokenTypes,
50544
+ TokenMap: new Map(TokenTypes.map((type, i) => [type, i]))
50545
+ };
50546
+
50037
50547
  // src/components/chat/ChatMessage.tsx
50038
50548
  var jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
50549
+ var T_IDENTIFIER2 = 0;
50550
+ var T_KEYWORD2 = 1;
50551
+ var T_STRING2 = 2;
50552
+ var T_CLS_NUMBER2 = 3;
50553
+ var T_PROPERTY2 = 4;
50554
+ var T_ENTITY2 = 5;
50555
+ var T_JSX_LITERAL = 6;
50556
+ var T_SIGN2 = 7;
50557
+ var T_COMMENT2 = 8;
50558
+ var T_BREAK2 = 9;
50559
+ var T_SPACE2 = 10;
50560
+ var JS_LANGS = new Set([
50561
+ "js",
50562
+ "javascript",
50563
+ "jsx",
50564
+ "ts",
50565
+ "typescript",
50566
+ "tsx",
50567
+ "mjs",
50568
+ "cjs"
50569
+ ]);
50570
+ function tokenColor(type) {
50571
+ switch (type) {
50572
+ case T_KEYWORD2:
50573
+ return TOKEN_KEYWORD;
50574
+ case T_STRING2:
50575
+ return TOKEN_STRING;
50576
+ case T_CLS_NUMBER2:
50577
+ return TOKEN_NUMBER;
50578
+ case T_PROPERTY2:
50579
+ return TOKEN_PROPERTY;
50580
+ case T_ENTITY2:
50581
+ return TOKEN_ENTITY;
50582
+ case T_JSX_LITERAL:
50583
+ return TOKEN_TEXT;
50584
+ case T_SIGN2:
50585
+ return TOKEN_MUTED;
50586
+ case T_COMMENT2:
50587
+ return TOKEN_COMMENT;
50588
+ case T_IDENTIFIER2:
50589
+ return TOKEN_TEXT;
50590
+ default:
50591
+ return TOKEN_TEXT;
50592
+ }
50593
+ }
50594
+ var PYTHON_KW = new Set([
50595
+ "def",
50596
+ "class",
50597
+ "import",
50598
+ "from",
50599
+ "return",
50600
+ "if",
50601
+ "elif",
50602
+ "else",
50603
+ "for",
50604
+ "while",
50605
+ "in",
50606
+ "not",
50607
+ "and",
50608
+ "or",
50609
+ "is",
50610
+ "None",
50611
+ "True",
50612
+ "False",
50613
+ "try",
50614
+ "except",
50615
+ "finally",
50616
+ "with",
50617
+ "as",
50618
+ "pass",
50619
+ "break",
50620
+ "continue",
50621
+ "raise",
50622
+ "yield",
50623
+ "lambda",
50624
+ "async",
50625
+ "await",
50626
+ "del",
50627
+ "global",
50628
+ "nonlocal",
50629
+ "assert"
50630
+ ]);
50631
+ var RUST_KW = new Set([
50632
+ "fn",
50633
+ "let",
50634
+ "mut",
50635
+ "const",
50636
+ "struct",
50637
+ "enum",
50638
+ "impl",
50639
+ "trait",
50640
+ "pub",
50641
+ "use",
50642
+ "mod",
50643
+ "match",
50644
+ "if",
50645
+ "else",
50646
+ "loop",
50647
+ "while",
50648
+ "for",
50649
+ "in",
50650
+ "return",
50651
+ "self",
50652
+ "Self",
50653
+ "super",
50654
+ "where",
50655
+ "type",
50656
+ "as",
50657
+ "ref",
50658
+ "move",
50659
+ "unsafe",
50660
+ "extern",
50661
+ "dyn",
50662
+ "async",
50663
+ "await",
50664
+ "true",
50665
+ "false",
50666
+ "Some",
50667
+ "None",
50668
+ "Ok",
50669
+ "Err"
50670
+ ]);
50671
+ var GO_KW = new Set([
50672
+ "func",
50673
+ "var",
50674
+ "const",
50675
+ "type",
50676
+ "struct",
50677
+ "interface",
50678
+ "package",
50679
+ "import",
50680
+ "return",
50681
+ "if",
50682
+ "else",
50683
+ "for",
50684
+ "range",
50685
+ "switch",
50686
+ "case",
50687
+ "default",
50688
+ "break",
50689
+ "continue",
50690
+ "goto",
50691
+ "defer",
50692
+ "go",
50693
+ "chan",
50694
+ "map",
50695
+ "make",
50696
+ "new",
50697
+ "nil",
50698
+ "true",
50699
+ "false",
50700
+ "error"
50701
+ ]);
50702
+ var SHELL_KW = new Set([
50703
+ "if",
50704
+ "then",
50705
+ "else",
50706
+ "elif",
50707
+ "fi",
50708
+ "for",
50709
+ "do",
50710
+ "done",
50711
+ "while",
50712
+ "case",
50713
+ "esac",
50714
+ "in",
50715
+ "function",
50716
+ "return",
50717
+ "echo",
50718
+ "export",
50719
+ "local",
50720
+ "source",
50721
+ "exit"
50722
+ ]);
50723
+ var CSS_AT = /^@[\w-]+/;
50724
+ var CSS_PROP = /^[\w-]+(?=\s*:)/;
50725
+ function tokenizeGeneric(code, lang) {
50726
+ const keywords = lang === "python" || lang === "py" ? PYTHON_KW : lang === "rust" || lang === "rs" ? RUST_KW : lang === "go" ? GO_KW : lang === "bash" || lang === "sh" || lang === "shell" || lang === "zsh" ? SHELL_KW : new Set;
50727
+ const lines = code.split(`
50728
+ `);
50729
+ return lines.map((line) => {
50730
+ const tokens = [];
50731
+ let i = 0;
50732
+ const push = (color, text) => {
50733
+ if (text)
50734
+ tokens.push({ color, text });
50735
+ };
50736
+ while (i < line.length) {
50737
+ const rest2 = line.slice(i);
50738
+ const commentPrefixes = lang === "python" || lang === "py" ? ["#"] : lang === "bash" || lang === "sh" || lang === "shell" || lang === "zsh" ? ["#"] : lang === "css" || lang === "scss" ? ["//", "/*"] : lang === "html" || lang === "xml" ? ["<!--"] : lang === "sql" ? ["--", "#"] : ["//", "#"];
50739
+ let matchedComment = false;
50740
+ for (const prefix of commentPrefixes) {
50741
+ if (rest2.startsWith(prefix)) {
50742
+ push(TOKEN_COMMENT, line.slice(i));
50743
+ i = line.length;
50744
+ matchedComment = true;
50745
+ break;
50746
+ }
50747
+ }
50748
+ if (matchedComment)
50749
+ continue;
50750
+ if (line[i] === '"' || line[i] === "'" || line[i] === "`") {
50751
+ const quote = line[i];
50752
+ let j = i + 1;
50753
+ while (j < line.length) {
50754
+ if (line[j] === "\\") {
50755
+ j += 2;
50756
+ continue;
50757
+ }
50758
+ if (line[j] === quote) {
50759
+ j++;
50760
+ break;
50761
+ }
50762
+ j++;
50763
+ }
50764
+ push(TOKEN_STRING, line.slice(i, j));
50765
+ i = j;
50766
+ continue;
50767
+ }
50768
+ const numMatch = rest2.match(/^-?\d+\.?\d*/);
50769
+ if (numMatch && (i === 0 || !/\w/.test(line[i - 1] ?? ""))) {
50770
+ push(TOKEN_NUMBER, numMatch[0]);
50771
+ i += numMatch[0].length;
50772
+ continue;
50773
+ }
50774
+ if (lang === "css" || lang === "scss") {
50775
+ const atMatch = rest2.match(CSS_AT);
50776
+ if (atMatch) {
50777
+ push(TOKEN_KEYWORD, atMatch[0]);
50778
+ i += atMatch[0].length;
50779
+ continue;
50780
+ }
50781
+ const propMatch = rest2.match(CSS_PROP);
50782
+ if (propMatch) {
50783
+ push(TOKEN_PROPERTY, propMatch[0]);
50784
+ i += propMatch[0].length;
50785
+ continue;
50786
+ }
50787
+ }
50788
+ if ((lang === "html" || lang === "xml") && line[i] === "<") {
50789
+ const tagMatch = rest2.match(/^<\/?[\w:-]+/);
50790
+ if (tagMatch) {
50791
+ push(TOKEN_ENTITY, tagMatch[0]);
50792
+ i += tagMatch[0].length;
50793
+ continue;
50794
+ }
50795
+ }
50796
+ const wordMatch = rest2.match(/^[a-zA-Z_$][\w$]*/);
50797
+ if (wordMatch) {
50798
+ const word = wordMatch[0];
50799
+ push(keywords.has(word) ? TOKEN_KEYWORD : TOKEN_TEXT, word);
50800
+ i += word.length;
50801
+ continue;
50802
+ }
50803
+ const opMatch = rest2.match(/^[^\w\s"'`]+/);
50804
+ if (opMatch) {
50805
+ push(TOKEN_MUTED, opMatch[0]);
50806
+ i += opMatch[0].length;
50807
+ continue;
50808
+ }
50809
+ push(TOKEN_TEXT, line[i]);
50810
+ i++;
50811
+ }
50812
+ return tokens;
50813
+ });
50814
+ }
50815
+ function HighlightedLine({ tokens }) {
50816
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50817
+ children: [
50818
+ " ",
50819
+ tokens.map((t, i) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50820
+ color: t.color,
50821
+ children: t.text
50822
+ }, i, false, undefined, this))
50823
+ ]
50824
+ }, undefined, true, undefined, this);
50825
+ }
50826
+ function CodeBlock({ lang, code }) {
50827
+ const normalizedLang = lang.toLowerCase().trim();
50828
+ let lines;
50829
+ if (JS_LANGS.has(normalizedLang)) {
50830
+ const tokens = tokenize3(code);
50831
+ const lineAccum = [[]];
50832
+ for (const [type, value] of tokens) {
50833
+ if (type === T_BREAK2) {
50834
+ lineAccum.push([]);
50835
+ } else if (type !== T_SPACE2) {
50836
+ lineAccum[lineAccum.length - 1].push({
50837
+ color: tokenColor(type),
50838
+ text: value
50839
+ });
50840
+ } else {
50841
+ lineAccum[lineAccum.length - 1].push({
50842
+ color: TOKEN_TEXT,
50843
+ text: value
50844
+ });
50845
+ }
50846
+ }
50847
+ lines = lineAccum;
50848
+ } else if (normalizedLang) {
50849
+ lines = tokenizeGeneric(code, normalizedLang);
50850
+ } else {
50851
+ lines = code.split(`
50852
+ `).map((l) => [{ color: TOKEN_TEXT, text: l }]);
50853
+ }
50854
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50855
+ flexDirection: "column",
50856
+ marginY: 1,
50857
+ marginLeft: 2,
50858
+ children: [
50859
+ normalizedLang ? /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50860
+ color: TOKEN_MUTED,
50861
+ dimColor: true,
50862
+ children: normalizedLang
50863
+ }, undefined, false, undefined, this) : null,
50864
+ lines.map((lineTokens, i) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(HighlightedLine, {
50865
+ tokens: lineTokens
50866
+ }, i, false, undefined, this))
50867
+ ]
50868
+ }, undefined, true, undefined, this);
50869
+ }
50039
50870
  function InlineText({ text }) {
50040
- const parts = text.split(/(`[^`]+`|\*\*[^*]+\*\*)/g);
50871
+ const parts = text.split(/(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)/g);
50041
50872
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(jsx_dev_runtime19.Fragment, {
50042
50873
  children: parts.map((part, i) => {
50043
- if (part.startsWith("`") && part.endsWith("`")) {
50874
+ if (part.startsWith("**") && part.endsWith("**")) {
50044
50875
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50045
- color: ACCENT,
50876
+ bold: true,
50877
+ color: TOKEN_TEXT,
50878
+ children: part.slice(2, -2)
50879
+ }, i, false, undefined, this);
50880
+ }
50881
+ if (part.startsWith("*") && part.endsWith("*") && part.length > 2) {
50882
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50883
+ italic: true,
50884
+ color: TOKEN_TEXT,
50046
50885
  children: part.slice(1, -1)
50047
50886
  }, i, false, undefined, this);
50048
50887
  }
50049
- if (part.startsWith("**") && part.endsWith("**")) {
50888
+ if (part.startsWith("`") && part.endsWith("`")) {
50050
50889
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50051
- bold: true,
50052
- color: "white",
50053
- children: part.slice(2, -2)
50890
+ color: ACCENT,
50891
+ children: part.slice(1, -1)
50054
50892
  }, i, false, undefined, this);
50055
50893
  }
50056
50894
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50057
- color: "white",
50895
+ color: TOKEN_TEXT,
50058
50896
  children: part
50059
50897
  }, i, false, undefined, this);
50060
50898
  })
50061
50899
  }, undefined, false, undefined, this);
50062
50900
  }
50063
- function CodeBlock({ lang, code }) {
50901
+ function Heading({ level, text }) {
50902
+ if (level === 1) {
50903
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50904
+ marginTop: 1,
50905
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50906
+ color: ACCENT,
50907
+ bold: true,
50908
+ underline: true,
50909
+ children: text
50910
+ }, undefined, false, undefined, this)
50911
+ }, undefined, false, undefined, this);
50912
+ }
50913
+ if (level === 2) {
50914
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50915
+ marginTop: 1,
50916
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50917
+ color: ACCENT,
50918
+ bold: true,
50919
+ children: text
50920
+ }, undefined, false, undefined, this)
50921
+ }, undefined, false, undefined, this);
50922
+ }
50064
50923
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50065
- flexDirection: "column",
50066
- marginY: 1,
50067
- marginLeft: 2,
50924
+ marginTop: 1,
50925
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50926
+ color: TOKEN_TEXT,
50927
+ bold: true,
50928
+ children: text
50929
+ }, undefined, false, undefined, this)
50930
+ }, undefined, false, undefined, this);
50931
+ }
50932
+ function BulletItem({ text }) {
50933
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50934
+ gap: 1,
50068
50935
  children: [
50069
- lang && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50070
- color: "gray",
50071
- children: lang
50072
- }, undefined, false, undefined, this),
50073
- code.split(`
50074
- `).map((line, i) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50936
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50075
50937
  color: ACCENT,
50938
+ children: "*"
50939
+ }, undefined, false, undefined, this),
50940
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50941
+ flexShrink: 1,
50942
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
50943
+ text
50944
+ }, undefined, false, undefined, this)
50945
+ }, undefined, false, undefined, this)
50946
+ ]
50947
+ }, undefined, true, undefined, this);
50948
+ }
50949
+ function NumberedItem({ num, text }) {
50950
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50951
+ gap: 1,
50952
+ children: [
50953
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50954
+ color: TOKEN_MUTED,
50076
50955
  children: [
50077
- " ",
50078
- line
50956
+ num,
50957
+ "."
50079
50958
  ]
50080
- }, i, true, undefined, this))
50959
+ }, undefined, true, undefined, this),
50960
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50961
+ flexShrink: 1,
50962
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
50963
+ text
50964
+ }, undefined, false, undefined, this)
50965
+ }, undefined, false, undefined, this)
50081
50966
  ]
50082
50967
  }, undefined, true, undefined, this);
50083
50968
  }
50084
- function MessageBody({ content }) {
50085
- const segments = content.split(/(```[\s\S]*?```)/g);
50969
+ function BlockQuote({ text }) {
50086
50970
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50087
- flexDirection: "column",
50088
- children: segments.map((seg, si) => {
50089
- if (seg.startsWith("```")) {
50090
- const lines2 = seg.slice(3).split(`
50971
+ gap: 1,
50972
+ marginLeft: 1,
50973
+ children: [
50974
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50975
+ color: TOKEN_MUTED,
50976
+ children: "│"
50977
+ }, undefined, false, undefined, this),
50978
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50979
+ color: TOKEN_MUTED,
50980
+ dimColor: true,
50981
+ children: text
50982
+ }, undefined, false, undefined, this)
50983
+ ]
50984
+ }, undefined, true, undefined, this);
50985
+ }
50986
+ function parseBlocks(content) {
50987
+ const blocks = [];
50988
+ const segments = content.split(/(```[\s\S]*?```)/g);
50989
+ for (const seg of segments) {
50990
+ if (seg.startsWith("```")) {
50991
+ const lines = seg.slice(3).split(`
50091
50992
  `);
50092
- const lang = lines2[0]?.trim() ?? "";
50093
- const code = lines2.slice(1).join(`
50993
+ const lang = lines[0]?.trim() ?? "";
50994
+ const code = lines.slice(1).join(`
50094
50995
  `).replace(/```\s*$/, "").trimEnd();
50095
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(CodeBlock, {
50096
- lang,
50097
- code
50098
- }, si, false, undefined, this);
50099
- }
50100
- const lines = seg.split(`
50101
- `).filter((l) => l.trim() !== "");
50102
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50103
- flexDirection: "column",
50104
- children: lines.map((line, li) => {
50105
- if (line.match(/^[-*•]\s/)) {
50106
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50107
- gap: 1,
50108
- children: [
50109
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50110
- color: ACCENT,
50111
- children: "*"
50112
- }, undefined, false, undefined, this),
50113
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
50114
- text: line.slice(2).trim()
50115
- }, undefined, false, undefined, this)
50116
- ]
50117
- }, li, true, undefined, this);
50118
- }
50119
- if (line.match(/^\d+\.\s/)) {
50120
- const num = line.match(/^(\d+)\.\s/)[1];
50121
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50122
- gap: 1,
50123
- children: [
50124
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50125
- color: "gray",
50126
- children: [
50127
- num,
50128
- "."
50129
- ]
50130
- }, undefined, true, undefined, this),
50131
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
50132
- text: line.replace(/^\d+\.\s/, "").trim()
50133
- }, undefined, false, undefined, this)
50134
- ]
50135
- }, li, true, undefined, this);
50136
- }
50996
+ blocks.push({ type: "code", lang, code });
50997
+ continue;
50998
+ }
50999
+ for (const line of seg.split(`
51000
+ `)) {
51001
+ const trimmed = line.trim();
51002
+ if (!trimmed)
51003
+ continue;
51004
+ const h3 = trimmed.match(/^### (.+)$/);
51005
+ const h2 = trimmed.match(/^## (.+)$/);
51006
+ const h1 = trimmed.match(/^# (.+)$/);
51007
+ if (h3) {
51008
+ blocks.push({ type: "heading", level: 3, text: h3[1] });
51009
+ continue;
51010
+ }
51011
+ if (h2) {
51012
+ blocks.push({ type: "heading", level: 2, text: h2[1] });
51013
+ continue;
51014
+ }
51015
+ if (h1) {
51016
+ blocks.push({ type: "heading", level: 1, text: h1[1] });
51017
+ continue;
51018
+ }
51019
+ if (/^[-*_]{3,}$/.test(trimmed)) {
51020
+ blocks.push({ type: "hr" });
51021
+ continue;
51022
+ }
51023
+ if (trimmed.startsWith("> ")) {
51024
+ blocks.push({ type: "blockquote", text: trimmed.slice(2).trim() });
51025
+ continue;
51026
+ }
51027
+ if (/^[-*•]\s/.test(trimmed)) {
51028
+ blocks.push({ type: "bullet", text: trimmed.slice(2).trim() });
51029
+ continue;
51030
+ }
51031
+ const numMatch = trimmed.match(/^(\d+)\.\s(.+)/);
51032
+ if (numMatch) {
51033
+ blocks.push({
51034
+ type: "numbered",
51035
+ num: numMatch[1],
51036
+ text: numMatch[2]
51037
+ });
51038
+ continue;
51039
+ }
51040
+ blocks.push({ type: "paragraph", text: trimmed });
51041
+ }
51042
+ }
51043
+ return blocks;
51044
+ }
51045
+ function MessageBody({ content }) {
51046
+ const blocks = parseBlocks(content);
51047
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
51048
+ flexDirection: "column",
51049
+ children: blocks.map((block, i) => {
51050
+ switch (block.type) {
51051
+ case "heading":
51052
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Heading, {
51053
+ level: block.level,
51054
+ text: block.text
51055
+ }, i, false, undefined, this);
51056
+ case "code":
51057
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(CodeBlock, {
51058
+ lang: block.lang,
51059
+ code: block.code
51060
+ }, i, false, undefined, this);
51061
+ case "bullet":
51062
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(BulletItem, {
51063
+ text: block.text
51064
+ }, i, false, undefined, this);
51065
+ case "numbered":
51066
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(NumberedItem, {
51067
+ num: block.num,
51068
+ text: block.text
51069
+ }, i, false, undefined, this);
51070
+ case "blockquote":
51071
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(BlockQuote, {
51072
+ text: block.text
51073
+ }, i, false, undefined, this);
51074
+ case "hr":
51075
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
51076
+ marginY: 1,
51077
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
51078
+ color: TOKEN_MUTED,
51079
+ dimColor: true,
51080
+ children: "─".repeat(40)
51081
+ }, undefined, false, undefined, this)
51082
+ }, i, false, undefined, this);
51083
+ case "paragraph":
50137
51084
  return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50138
51085
  children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
50139
- text: line
51086
+ text: block.text
50140
51087
  }, undefined, false, undefined, this)
50141
- }, li, false, undefined, this);
50142
- })
50143
- }, si, false, undefined, this);
51088
+ }, i, false, undefined, this);
51089
+ }
50144
51090
  })
50145
51091
  }, undefined, false, undefined, this);
50146
51092
  }
@@ -50151,11 +51097,11 @@ function StaticMessage({ msg }) {
50151
51097
  gap: 1,
50152
51098
  children: [
50153
51099
  /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50154
- color: "gray",
51100
+ color: TOKEN_MUTED,
50155
51101
  children: ">"
50156
51102
  }, undefined, false, undefined, this),
50157
51103
  /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50158
- color: "white",
51104
+ color: TOKEN_TEXT,
50159
51105
  bold: true,
50160
51106
  children: msg.content
50161
51107
  }, undefined, false, undefined, this)
@@ -50190,7 +51136,7 @@ function StaticMessage({ msg }) {
50190
51136
  children: icon
50191
51137
  }, undefined, false, undefined, this),
50192
51138
  /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50193
- color: msg.approved ? "gray" : "red",
51139
+ color: msg.approved ? TOKEN_MUTED : "red",
50194
51140
  dimColor: !msg.approved,
50195
51141
  children: label
50196
51142
  }, undefined, false, undefined, this),
@@ -50203,7 +51149,7 @@ function StaticMessage({ msg }) {
50203
51149
  msg.approved && msg.result && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
50204
51150
  marginLeft: 2,
50205
51151
  children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50206
- color: "gray",
51152
+ color: TOKEN_MUTED,
50207
51153
  children: [
50208
51154
  msg.result.split(`
50209
51155
  `)[0]?.slice(0, 120),
@@ -50237,11 +51183,11 @@ function StaticMessage({ msg }) {
50237
51183
  gap: 1,
50238
51184
  children: [
50239
51185
  /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50240
- color: msg.applied ? "green" : "gray",
51186
+ color: msg.applied ? "green" : TOKEN_MUTED,
50241
51187
  children: msg.applied ? "✓" : "·"
50242
51188
  }, undefined, false, undefined, this),
50243
51189
  /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
50244
- color: msg.applied ? "green" : "gray",
51190
+ color: msg.applied ? "green" : TOKEN_MUTED,
50245
51191
  dimColor: !msg.applied,
50246
51192
  children: msg.applied ? "changes applied" : "changes skipped"
50247
51193
  }, undefined, false, undefined, this)
@@ -52349,6 +53295,7 @@ var ChatRunner = ({ repoPath }) => {
52349
53295
  const [showTimeline, setShowTimeline] = import_react48.useState(false);
52350
53296
  const [showReview, setShowReview] = import_react48.useState(false);
52351
53297
  const [autoApprove, setAutoApprove] = import_react48.useState(false);
53298
+ const abortControllerRef = import_react48.useRef(null);
52352
53299
  const toolResultCache = import_react48.useRef(new Map);
52353
53300
  const inputBuffer = import_react48.useRef("");
52354
53301
  const flushTimer = import_react48.useRef(null);
@@ -52369,6 +53316,10 @@ var ChatRunner = ({ repoPath }) => {
52369
53316
  }, 16);
52370
53317
  };
52371
53318
  const handleError = (currentAll) => (err) => {
53319
+ if (err instanceof Error && err.name === "AbortError") {
53320
+ setStage({ type: "idle" });
53321
+ return;
53322
+ }
52372
53323
  const errMsg = {
52373
53324
  role: "assistant",
52374
53325
  content: `Error: ${err instanceof Error ? err.message : "Something went wrong"}`,
@@ -52378,7 +53329,11 @@ var ChatRunner = ({ repoPath }) => {
52378
53329
  setCommitted((prev) => [...prev, errMsg]);
52379
53330
  setStage({ type: "idle" });
52380
53331
  };
52381
- const processResponse = (raw, currentAll) => {
53332
+ const processResponse = (raw, currentAll, signal) => {
53333
+ if (signal.aborted) {
53334
+ setStage({ type: "idle" });
53335
+ return;
53336
+ }
52382
53337
  const parsed = parseResponse(raw);
52383
53338
  if (parsed.kind === "changes") {
52384
53339
  if (parsed.patches.length === 0) {
@@ -52532,8 +53487,10 @@ var ChatRunner = ({ repoPath }) => {
52532
53487
  const withTool = [...currentAll, toolMsg];
52533
53488
  setAllMessages(withTool);
52534
53489
  setCommitted((prev) => [...prev, toolMsg]);
53490
+ const nextAbort = new AbortController;
53491
+ abortControllerRef.current = nextAbort;
52535
53492
  setStage({ type: "thinking" });
52536
- callChat(provider, systemPrompt, withTool).then((r) => processResponse(r, withTool)).catch(handleError(withTool));
53493
+ callChat(provider, systemPrompt, withTool, nextAbort.signal).then((r) => processResponse(r, withTool, nextAbort.signal)).catch(handleError(withTool));
52537
53494
  };
52538
53495
  if (autoApprove && isSafeTool) {
52539
53496
  executeAndContinue(true);
@@ -52621,12 +53578,20 @@ var ChatRunner = ({ repoPath }) => {
52621
53578
  setCommitted((prev) => [...prev, userMsg]);
52622
53579
  setAllMessages(nextAll);
52623
53580
  toolResultCache.current.clear();
53581
+ const abort = new AbortController;
53582
+ abortControllerRef.current = abort;
52624
53583
  setStage({ type: "thinking" });
52625
- callChat(provider, systemPrompt, nextAll).then((raw) => processResponse(raw, nextAll)).catch(handleError(nextAll));
53584
+ callChat(provider, systemPrompt, nextAll, abort.signal).then((raw) => processResponse(raw, nextAll, abort.signal)).catch(handleError(nextAll));
52626
53585
  };
52627
53586
  use_input_default((input, key) => {
52628
53587
  if (showTimeline)
52629
53588
  return;
53589
+ if (stage.type === "thinking" && key.escape) {
53590
+ abortControllerRef.current?.abort();
53591
+ abortControllerRef.current = null;
53592
+ setStage({ type: "idle" });
53593
+ return;
53594
+ }
52630
53595
  if (stage.type === "idle") {
52631
53596
  if (key.ctrl && input === "c") {
52632
53597
  process.exit(0);
@@ -52958,6 +53923,11 @@ Tip: type /timeline to browse commit history.`,
52958
53923
  }, undefined, false, undefined, this),
52959
53924
  /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(TypewriterText, {
52960
53925
  text: thinkingPhrase
53926
+ }, undefined, false, undefined, this),
53927
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
53928
+ color: "gray",
53929
+ dimColor: true,
53930
+ children: "· esc cancel"
52961
53931
  }, undefined, false, undefined, this)
52962
53932
  ]
52963
53933
  }, undefined, true, undefined, this),