@ashx-j/lunr 0.2.22 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/README.md +5 -3
  3. package/dist/builtin-extensions/lunr-browser.d.ts +7 -1
  4. package/dist/builtin-extensions/lunr-browser.d.ts.map +1 -1
  5. package/dist/builtin-extensions/lunr-browser.js +116 -3
  6. package/dist/builtin-extensions/lunr-browser.js.map +1 -1
  7. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +1 -1
  9. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  10. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +2 -0
  11. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
  12. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +9 -0
  13. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +41 -3
  16. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +4 -0
  19. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +3 -2
  23. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -1
  24. package/dist/core/agent-session.d.ts +19 -0
  25. package/dist/core/agent-session.d.ts.map +1 -1
  26. package/dist/core/agent-session.js +230 -103
  27. package/dist/core/agent-session.js.map +1 -1
  28. package/dist/core/settings-manager.d.ts +4 -0
  29. package/dist/core/settings-manager.d.ts.map +1 -1
  30. package/dist/core/settings-manager.js +9 -0
  31. package/dist/core/settings-manager.js.map +1 -1
  32. package/dist/core/subagent-wait-interruption.d.ts +11 -0
  33. package/dist/core/subagent-wait-interruption.d.ts.map +1 -0
  34. package/dist/core/subagent-wait-interruption.js +19 -0
  35. package/dist/core/subagent-wait-interruption.js.map +1 -0
  36. package/dist/core/system-prompt.d.ts.map +1 -1
  37. package/dist/core/system-prompt.js +3 -1
  38. package/dist/core/system-prompt.js.map +1 -1
  39. package/dist/core/tools/render-utils.d.ts +3 -3
  40. package/dist/core/tools/render-utils.d.ts.map +1 -1
  41. package/dist/core/tools/render-utils.js +3 -3
  42. package/dist/core/tools/render-utils.js.map +1 -1
  43. package/dist/modes/interactive/components/assistant-message.d.ts +10 -2
  44. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  45. package/dist/modes/interactive/components/assistant-message.js +29 -5
  46. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  47. package/dist/modes/interactive/components/copyable-text.d.ts +2 -6
  48. package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -1
  49. package/dist/modes/interactive/components/copyable-text.js +26 -35
  50. package/dist/modes/interactive/components/copyable-text.js.map +1 -1
  51. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  52. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  53. package/dist/modes/interactive/components/settings-selector.js +13 -0
  54. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  55. package/dist/modes/interactive/components/thinking-tail.d.ts +9 -2
  56. package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
  57. package/dist/modes/interactive/components/thinking-tail.js +43 -1
  58. package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
  59. package/dist/modes/interactive/components/tool-execution.d.ts +4 -3
  60. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  61. package/dist/modes/interactive/components/tool-execution.js +34 -45
  62. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  63. package/dist/modes/interactive/interactive-mode.d.ts +6 -0
  64. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  65. package/dist/modes/interactive/interactive-mode.js +118 -39
  66. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  67. package/dist/modes/interactive/theme/theme.d.ts +1 -0
  68. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  69. package/dist/modes/interactive/theme/theme.js +23 -0
  70. package/dist/modes/interactive/theme/theme.js.map +1 -1
  71. package/dist/node-runtime/{agent-session-services-NQ6GKOIK.js → agent-session-services-GZVSOGYR.js} +7 -7
  72. package/dist/node-runtime/{builtin-extensions-GVC6IFDU.js → builtin-extensions-QVCXNQT4.js} +3 -3
  73. package/dist/node-runtime/{chunk-6B2POMK7.js → chunk-6VYZ5UFP.js} +1 -1
  74. package/dist/node-runtime/{chunk-VJPTNWAP.js → chunk-DD5YWFSJ.js} +1 -1
  75. package/dist/node-runtime/{chunk-TDL7UWJ7.js → chunk-DQMGU675.js} +173 -57
  76. package/dist/node-runtime/{chunk-V2A7CEXK.js → chunk-EKVFP6YF.js} +2 -2
  77. package/dist/node-runtime/{chunk-5BNJ4JUH.js → chunk-GJ2RDBRL.js} +1 -1
  78. package/dist/node-runtime/{chunk-GNN7H3B7.js → chunk-GS42T6MX.js} +1 -1
  79. package/dist/node-runtime/{chunk-PC2Z5TKZ.js → chunk-HMBGROQK.js} +3 -3
  80. package/dist/node-runtime/{chunk-GJSAD4AB.js → chunk-HPUP7E4T.js} +10 -10
  81. package/dist/node-runtime/{chunk-IVXYUAJE.js → chunk-IF24A3FH.js} +1 -1
  82. package/dist/node-runtime/{chunk-BFNXONG3.js → chunk-LFZDVKSP.js} +2 -2
  83. package/dist/node-runtime/{chunk-EQ63ANHL.js → chunk-LLUIPGDR.js} +210 -125
  84. package/dist/node-runtime/{chunk-ORH324EP.js → chunk-PCEW76PM.js} +3 -3
  85. package/dist/node-runtime/{chunk-WADV2VDS.js → chunk-QAZOULTU.js} +7 -0
  86. package/dist/node-runtime/{chunk-6427XAWG.js → chunk-QH6YL7VK.js} +3 -3
  87. package/dist/node-runtime/{chunk-7QWNYZDI.js → chunk-RDDAZOMU.js} +16 -0
  88. package/dist/node-runtime/{chunk-QDGKKKUM.js → chunk-RIR5EDDJ.js} +1 -1
  89. package/dist/node-runtime/{chunk-H3XF4UVQ.js → chunk-RWTKOC3B.js} +1 -1
  90. package/dist/node-runtime/{chunk-IQIEU7SB.js → chunk-TVJUOJZJ.js} +2 -2
  91. package/dist/node-runtime/{chunk-UAFLNHSH.js → chunk-W64JC4E7.js} +8 -8
  92. package/dist/node-runtime/{chunk-LMBNLFXQ.js → chunk-X3URCYCU.js} +4 -4
  93. package/dist/node-runtime/{chunk-VSSXXL36.js → chunk-YDO2F2IA.js} +2 -2
  94. package/dist/node-runtime/{chunk-IWOWXRWU.js → chunk-YHQ3NBB3.js} +15 -15
  95. package/dist/node-runtime/cli-runtime.js +1 -1
  96. package/dist/node-runtime/{command-3JHHXOPX.js → command-PDVTBRWA.js} +3 -3
  97. package/dist/node-runtime/{commands-2JVNFGMQ.js → commands-XDCFGIGW.js} +5 -5
  98. package/dist/node-runtime/{export-html-KBFVV63J.js → export-html-KSOIMVPI.js} +1 -1
  99. package/dist/node-runtime/{extension-input-K24TVKVW.js → extension-input-E7BJZ35H.js} +4 -4
  100. package/dist/node-runtime/{extension-selector-SPNF7EDR.js → extension-selector-WU42XDTU.js} +4 -4
  101. package/dist/node-runtime/{gateway-VFO6SFKK.js → gateway-AYWM5DIO.js} +7 -7
  102. package/dist/node-runtime/index.js +17 -17
  103. package/dist/node-runtime/{install-cli-C3CF7O7N.js → install-cli-3BO4MMQ6.js} +1 -1
  104. package/dist/node-runtime/{interactive-mode-LOM6AIF6.js → interactive-mode-4MFRKAHG.js} +13 -13
  105. package/dist/node-runtime/{interactive-view-IDSCPPK7.js → interactive-view-TUZHCQM3.js} +5 -5
  106. package/dist/node-runtime/{lunr-browser-YNW7FTYX.js → lunr-browser-RYFIIVJN.js} +91 -4
  107. package/dist/node-runtime/{lunr-cron-BKHGNBKT.js → lunr-cron-YWXEPZMQ.js} +4 -4
  108. package/dist/node-runtime/main.js +14 -14
  109. package/dist/node-runtime/{mobile-commands-HMP25WBC.js → mobile-commands-LVHDAUDP.js} +4 -4
  110. package/dist/node-runtime/{package-manager-cli-VCK4E2RC.js → package-manager-cli-6GT3Z3CK.js} +9 -9
  111. package/dist/node-runtime/{pi-subagents-FEUDLJOE.js → pi-subagents-CDWK2AKY.js} +44 -10
  112. package/dist/node-runtime/rpc-entry.js +14 -14
  113. package/dist/node-runtime/{rpc-mode-P5ODXPEG.js → rpc-mode-O3XV4SID.js} +2 -2
  114. package/dist/node-runtime/{session-selector-LHRMJOKT.js → session-selector-GIM4DHQ2.js} +4 -4
  115. package/dist/node-runtime/{settings-manager-UUZ6NUXI.js → settings-manager-6VEMXRDL.js} +1 -1
  116. package/dist/node-runtime/{setup-NRXVZBLJ.js → setup-5SR2J35A.js} +1 -1
  117. package/dist/node-runtime/{subagent-executor-MLUMBWCP.js → subagent-executor-M5VWB3D3.js} +8 -4
  118. package/dist/node-runtime/{theme-U7IGOA7O.js → theme-UOO5RVFN.js} +1 -1
  119. package/dist/node-runtime/{update-cli-4TP25CNW.js → update-cli-UVKJWRRJ.js} +1 -1
  120. package/docs/features.md +2 -0
  121. package/docs/settings.md +1 -0
  122. package/docs/usage.md +2 -2
  123. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  124. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  125. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  126. package/examples/extensions/gondolin/package-lock.json +2 -2
  127. package/examples/extensions/gondolin/package.json +1 -1
  128. package/examples/extensions/sandbox/package-lock.json +2 -2
  129. package/examples/extensions/sandbox/package.json +1 -1
  130. package/examples/extensions/with-deps/package-lock.json +2 -2
  131. package/examples/extensions/with-deps/package.json +1 -1
  132. package/package.json +4 -4
@@ -1,4 +1,3 @@
1
- import type { MarkdownTheme } from "@ashx-j/lunr-tui";
2
1
  import { type Component } from "@ashx-j/lunr-tui";
3
2
  export type CopyableTextSegment = {
4
3
  type: "markdown";
@@ -14,16 +13,13 @@ export type CopyableTextStatus = "idle" | "copying" | "copied" | {
14
13
  error: string;
15
14
  };
16
15
  export declare class CopyableTextBlockComponent implements Component {
17
- private buttonRow;
18
- private buttonStart;
19
- private buttonEnd;
16
+ private renderedRows;
20
17
  private readonly payload;
21
18
  private readonly complete;
22
19
  private readonly outputPad;
23
- private readonly markdownTheme;
24
20
  private readonly status;
25
21
  private readonly onCopy;
26
- constructor(payload: string, complete: boolean, outputPad: number, markdownTheme: MarkdownTheme, status: CopyableTextStatus, onCopy: () => void);
22
+ constructor(payload: string, complete: boolean, outputPad: number, status: CopyableTextStatus, onCopy: () => void);
27
23
  invalidate(): void;
28
24
  render(width: number): string[];
29
25
  handleClick(localY: number, width: number, localX?: number): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"copyable-text.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/copyable-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAG3F,MAAM,MAAM,mBAAmB,GAC5B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAuD3E,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA0D/E;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF,qBAAa,0BAA2B,YAAW,SAAS;IAC3D,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,YACC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,MAAM,IAAI,EAQlB;IAED,UAAU,IAAI,IAAI,CAIjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0C9B;IAED,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAcnE;CACD","sourcesContent":["import type { MarkdownTheme } from \"@ashx-j/lunr-tui\";\nimport { type Component, truncateToWidth, wrapTextWithAnsi } from \"@ashx-j/lunr-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport type CopyableTextSegment =\n\t| { type: \"markdown\"; text: string }\n\t| { type: \"copyable\"; payload: string; complete: boolean; start: number };\n\ninterface SourceLine {\n\tstart: number;\n\tend: number;\n\ttext: string;\n}\n\ninterface FenceOpening {\n\tmarker: \"`\" | \"~\";\n\tlength: number;\n\tcopyable: boolean;\n}\n\nfunction sourceLines(source: string): SourceLine[] {\n\tconst lines: SourceLine[] = [];\n\tconst pattern = /([^\\r\\n]*)(\\r\\n|\\r|\\n|$)/g;\n\tfor (const match of source.matchAll(pattern)) {\n\t\tconst start = match.index;\n\t\tconst text = match[1];\n\t\tconst newline = match[2];\n\t\tlines.push({ start, end: start + text.length + newline.length, text });\n\t\tif (!newline) break;\n\t}\n\treturn lines;\n}\n\nfunction parseFenceOpening(line: string): FenceOpening | undefined {\n\tconst match = /^( {0,3})(`{3,}|~{3,})(.*)$/.exec(line);\n\tif (!match) return undefined;\n\tconst fence = match[2];\n\tconst info = match[3];\n\tif (fence[0] === \"`\" && info.includes(\"`\")) return undefined;\n\treturn {\n\t\tmarker: fence[0] as \"`\" | \"~\",\n\t\tlength: fence.length,\n\t\tcopyable: info.trim() === \"lunr-copy\",\n\t};\n}\n\nfunction isFenceClosing(line: string, opening: FenceOpening): boolean {\n\tconst match = /^( {0,3})(`+|~+)[ \\t]*$/.exec(line);\n\tif (!match) return false;\n\tconst fence = match[2];\n\treturn fence[0] === opening.marker && fence.length >= opening.length;\n}\n\nfunction payloadEndBeforeClosing(source: string, closingStart: number): number {\n\tif (closingStart >= 2 && source.slice(closingStart - 2, closingStart) === \"\\r\\n\") return closingStart - 2;\n\tif (closingStart >= 1 && (source[closingStart - 1] === \"\\n\" || source[closingStart - 1] === \"\\r\")) {\n\t\treturn closingStart - 1;\n\t}\n\treturn closingStart;\n}\n\nexport function parseCopyableTextSegments(source: string): CopyableTextSegment[] {\n\tconst lines = sourceLines(source);\n\tconst segments: CopyableTextSegment[] = [];\n\tlet emittedThrough = 0;\n\tlet lineIndex = 0;\n\n\twhile (lineIndex < lines.length) {\n\t\tconst openingLine = lines[lineIndex];\n\t\tconst opening = parseFenceOpening(openingLine.text);\n\t\tif (!opening) {\n\t\t\tlineIndex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet closingIndex = -1;\n\t\tfor (let i = lineIndex + 1; i < lines.length; i++) {\n\t\t\tif (isFenceClosing(lines[i].text, opening)) {\n\t\t\t\tclosingIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!opening.copyable) {\n\t\t\tif (closingIndex < 0) break;\n\t\t\tlineIndex = closingIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (openingLine.start > emittedThrough) {\n\t\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough, openingLine.start) });\n\t\t}\n\n\t\tconst payloadStart = openingLine.end;\n\t\tif (closingIndex < 0) {\n\t\t\tsegments.push({\n\t\t\t\ttype: \"copyable\",\n\t\t\t\tpayload: source.slice(payloadStart),\n\t\t\t\tcomplete: false,\n\t\t\t\tstart: openingLine.start,\n\t\t\t});\n\t\t\treturn segments;\n\t\t}\n\n\t\tconst closingLine = lines[closingIndex];\n\t\tsegments.push({\n\t\t\ttype: \"copyable\",\n\t\t\tpayload: source.slice(payloadStart, payloadEndBeforeClosing(source, closingLine.start)),\n\t\t\tcomplete: true,\n\t\t\tstart: openingLine.start,\n\t\t});\n\t\temittedThrough = closingLine.end;\n\t\tlineIndex = closingIndex + 1;\n\t}\n\n\tif (emittedThrough < source.length) {\n\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough) });\n\t}\n\treturn segments;\n}\n\nexport type CopyableTextStatus = \"idle\" | \"copying\" | \"copied\" | { error: string };\n\nexport class CopyableTextBlockComponent implements Component {\n\tprivate buttonRow = -1;\n\tprivate buttonStart = -1;\n\tprivate buttonEnd = -1;\n\tprivate readonly payload: string;\n\tprivate readonly complete: boolean;\n\tprivate readonly outputPad: number;\n\tprivate readonly markdownTheme: MarkdownTheme;\n\tprivate readonly status: CopyableTextStatus;\n\tprivate readonly onCopy: () => void;\n\n\tconstructor(\n\t\tpayload: string,\n\t\tcomplete: boolean,\n\t\toutputPad: number,\n\t\tmarkdownTheme: MarkdownTheme,\n\t\tstatus: CopyableTextStatus,\n\t\tonCopy: () => void,\n\t) {\n\t\tthis.payload = payload;\n\t\tthis.complete = complete;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.status = status;\n\t\tthis.onCopy = onCopy;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.buttonRow = -1;\n\t\tthis.buttonStart = -1;\n\t\tthis.buttonEnd = -1;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst pad = \" \".repeat(this.outputPad);\n\t\tconst contentWidth = Math.max(1, width - this.outputPad - 2);\n\t\tconst lines = [truncateToWidth(`${pad}${this.markdownTheme.codeBlockBorder(\"╭─ lunr-copy\")}`, width, \"\")];\n\t\tconst payloadLines = this.payload.replace(/\\t/g, \" \").split(\"\\n\");\n\n\t\tfor (const payloadLine of payloadLines) {\n\t\t\tfor (const wrappedLine of wrapTextWithAnsi(payloadLine, contentWidth)) {\n\t\t\t\tlines.push(\n\t\t\t\t\ttruncateToWidth(\n\t\t\t\t\t\t`${pad}${this.markdownTheme.codeBlockBorder(\"│ \")}${this.markdownTheme.codeBlock(wrappedLine)}`,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tlines.push(\n\t\t\ttruncateToWidth(\n\t\t\t\t`${pad}${this.markdownTheme.codeBlockBorder(this.complete ? \"╰─\" : \"╰─ receiving\")}`,\n\t\t\t\twidth,\n\t\t\t\t\"\",\n\t\t\t),\n\t\t);\n\n\t\tthis.buttonRow = -1;\n\t\tthis.buttonStart = -1;\n\t\tthis.buttonEnd = -1;\n\t\tif (this.complete) {\n\t\t\tconst button = \"[ Copy ]\";\n\t\t\tlet feedback = \"\";\n\t\t\tif (this.status === \"copying\") feedback = theme.fg(\"dim\", \" Copying...\");\n\t\t\telse if (this.status === \"copied\") feedback = theme.fg(\"success\", \" Copied\");\n\t\t\telse if (typeof this.status === \"object\") feedback = theme.fg(\"error\", ` Copy failed: ${this.status.error}`);\n\t\t\tthis.buttonRow = lines.length;\n\t\t\tthis.buttonStart = this.outputPad;\n\t\t\tthis.buttonEnd = Math.min(width, this.buttonStart + button.length);\n\t\t\tlines.push(truncateToWidth(`${pad}${theme.fg(\"accent\", button)}${feedback}`, width, \"\"));\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleClick(localY: number, width: number, localX?: number): boolean {\n\t\tthis.render(width);\n\t\tif (\n\t\t\t!this.complete ||\n\t\t\tthis.status === \"copying\" ||\n\t\t\tlocalX === undefined ||\n\t\t\tlocalY !== this.buttonRow ||\n\t\t\tlocalX < this.buttonStart ||\n\t\t\tlocalX >= this.buttonEnd\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.onCopy();\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"copyable-text.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/copyable-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmD,MAAM,wBAAwB,CAAC;AAGzG,MAAM,MAAM,mBAAmB,GAC5B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAuD3E,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA0D/E;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF,qBAAa,0BAA2B,YAAW,SAAS;IAC3D,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,YAAY,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,IAAI,EAMhH;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA8B9B;IAED,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAanE;CACD","sourcesContent":["import { type Component, truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"@ashx-j/lunr-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport type CopyableTextSegment =\n\t| { type: \"markdown\"; text: string }\n\t| { type: \"copyable\"; payload: string; complete: boolean; start: number };\n\ninterface SourceLine {\n\tstart: number;\n\tend: number;\n\ttext: string;\n}\n\ninterface FenceOpening {\n\tmarker: \"`\" | \"~\";\n\tlength: number;\n\tcopyable: boolean;\n}\n\nfunction sourceLines(source: string): SourceLine[] {\n\tconst lines: SourceLine[] = [];\n\tconst pattern = /([^\\r\\n]*)(\\r\\n|\\r|\\n|$)/g;\n\tfor (const match of source.matchAll(pattern)) {\n\t\tconst start = match.index;\n\t\tconst text = match[1];\n\t\tconst newline = match[2];\n\t\tlines.push({ start, end: start + text.length + newline.length, text });\n\t\tif (!newline) break;\n\t}\n\treturn lines;\n}\n\nfunction parseFenceOpening(line: string): FenceOpening | undefined {\n\tconst match = /^( {0,3})(`{3,}|~{3,})(.*)$/.exec(line);\n\tif (!match) return undefined;\n\tconst fence = match[2];\n\tconst info = match[3];\n\tif (fence[0] === \"`\" && info.includes(\"`\")) return undefined;\n\treturn {\n\t\tmarker: fence[0] as \"`\" | \"~\",\n\t\tlength: fence.length,\n\t\tcopyable: info.trim() === \"lunr-copy\",\n\t};\n}\n\nfunction isFenceClosing(line: string, opening: FenceOpening): boolean {\n\tconst match = /^( {0,3})(`+|~+)[ \\t]*$/.exec(line);\n\tif (!match) return false;\n\tconst fence = match[2];\n\treturn fence[0] === opening.marker && fence.length >= opening.length;\n}\n\nfunction payloadEndBeforeClosing(source: string, closingStart: number): number {\n\tif (closingStart >= 2 && source.slice(closingStart - 2, closingStart) === \"\\r\\n\") return closingStart - 2;\n\tif (closingStart >= 1 && (source[closingStart - 1] === \"\\n\" || source[closingStart - 1] === \"\\r\")) {\n\t\treturn closingStart - 1;\n\t}\n\treturn closingStart;\n}\n\nexport function parseCopyableTextSegments(source: string): CopyableTextSegment[] {\n\tconst lines = sourceLines(source);\n\tconst segments: CopyableTextSegment[] = [];\n\tlet emittedThrough = 0;\n\tlet lineIndex = 0;\n\n\twhile (lineIndex < lines.length) {\n\t\tconst openingLine = lines[lineIndex];\n\t\tconst opening = parseFenceOpening(openingLine.text);\n\t\tif (!opening) {\n\t\t\tlineIndex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet closingIndex = -1;\n\t\tfor (let i = lineIndex + 1; i < lines.length; i++) {\n\t\t\tif (isFenceClosing(lines[i].text, opening)) {\n\t\t\t\tclosingIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!opening.copyable) {\n\t\t\tif (closingIndex < 0) break;\n\t\t\tlineIndex = closingIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (openingLine.start > emittedThrough) {\n\t\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough, openingLine.start) });\n\t\t}\n\n\t\tconst payloadStart = openingLine.end;\n\t\tif (closingIndex < 0) {\n\t\t\tsegments.push({\n\t\t\t\ttype: \"copyable\",\n\t\t\t\tpayload: source.slice(payloadStart),\n\t\t\t\tcomplete: false,\n\t\t\t\tstart: openingLine.start,\n\t\t\t});\n\t\t\treturn segments;\n\t\t}\n\n\t\tconst closingLine = lines[closingIndex];\n\t\tsegments.push({\n\t\t\ttype: \"copyable\",\n\t\t\tpayload: source.slice(payloadStart, payloadEndBeforeClosing(source, closingLine.start)),\n\t\t\tcomplete: true,\n\t\t\tstart: openingLine.start,\n\t\t});\n\t\temittedThrough = closingLine.end;\n\t\tlineIndex = closingIndex + 1;\n\t}\n\n\tif (emittedThrough < source.length) {\n\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough) });\n\t}\n\treturn segments;\n}\n\nexport type CopyableTextStatus = \"idle\" | \"copying\" | \"copied\" | { error: string };\n\nexport class CopyableTextBlockComponent implements Component {\n\tprivate renderedRows = 0;\n\tprivate readonly payload: string;\n\tprivate readonly complete: boolean;\n\tprivate readonly outputPad: number;\n\tprivate readonly status: CopyableTextStatus;\n\tprivate readonly onCopy: () => void;\n\n\tconstructor(payload: string, complete: boolean, outputPad: number, status: CopyableTextStatus, onCopy: () => void) {\n\t\tthis.payload = payload;\n\t\tthis.complete = complete;\n\t\tthis.outputPad = outputPad;\n\t\tthis.status = status;\n\t\tthis.onCopy = onCopy;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.renderedRows = 0;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width <= 0) {\n\t\t\tthis.renderedRows = 0;\n\t\t\treturn [];\n\t\t}\n\n\t\tconst horizontalPad = Math.min(this.outputPad, Math.max(0, width - 1));\n\t\tconst pad = \" \".repeat(horizontalPad);\n\t\tconst contentWidth = Math.max(1, width - horizontalPad * 2);\n\t\tconst paint = (content: string): string => {\n\t\t\tconst line = truncateToWidth(`${pad}${content}`, width, \"\");\n\t\t\treturn theme.bg(\"userMessageBg\", `${line}${\" \".repeat(Math.max(0, width - visibleWidth(line)))}`);\n\t\t};\n\t\tconst lines = [paint(\"\")];\n\t\tconst payloadLines = this.payload.replace(/\\t/g, \" \").split(\"\\n\");\n\n\t\tfor (const payloadLine of payloadLines) {\n\t\t\tfor (const wrappedLine of wrapTextWithAnsi(payloadLine, contentWidth)) {\n\t\t\t\tlines.push(paint(theme.fg(\"userMessageText\", wrappedLine)));\n\t\t\t}\n\t\t}\n\n\t\tif (typeof this.status === \"object\") {\n\t\t\tfor (const wrappedLine of wrapTextWithAnsi(`Copy failed: ${this.status.error}`, contentWidth)) {\n\t\t\t\tlines.push(paint(theme.fg(\"error\", wrappedLine)));\n\t\t\t}\n\t\t}\n\t\tlines.push(paint(\"\"));\n\t\tthis.renderedRows = lines.length;\n\t\treturn lines;\n\t}\n\n\thandleClick(localY: number, width: number, localX?: number): boolean {\n\t\tthis.render(width);\n\t\tif (\n\t\t\t!this.complete ||\n\t\t\tthis.status === \"copying\" ||\n\t\t\tlocalY < 0 ||\n\t\t\tlocalY >= this.renderedRows ||\n\t\t\t(localX !== undefined && (localX < 0 || localX >= width))\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.onCopy();\n\t\treturn true;\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { truncateToWidth, wrapTextWithAnsi } from "@ashx-j/lunr-tui";
1
+ import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@ashx-j/lunr-tui";
2
2
  import { theme } from "../theme/theme.js";
3
3
  function sourceLines(source) {
4
4
  const lines = [];
@@ -96,66 +96,57 @@ export function parseCopyableTextSegments(source) {
96
96
  return segments;
97
97
  }
98
98
  export class CopyableTextBlockComponent {
99
- buttonRow = -1;
100
- buttonStart = -1;
101
- buttonEnd = -1;
99
+ renderedRows = 0;
102
100
  payload;
103
101
  complete;
104
102
  outputPad;
105
- markdownTheme;
106
103
  status;
107
104
  onCopy;
108
- constructor(payload, complete, outputPad, markdownTheme, status, onCopy) {
105
+ constructor(payload, complete, outputPad, status, onCopy) {
109
106
  this.payload = payload;
110
107
  this.complete = complete;
111
108
  this.outputPad = outputPad;
112
- this.markdownTheme = markdownTheme;
113
109
  this.status = status;
114
110
  this.onCopy = onCopy;
115
111
  }
116
112
  invalidate() {
117
- this.buttonRow = -1;
118
- this.buttonStart = -1;
119
- this.buttonEnd = -1;
113
+ this.renderedRows = 0;
120
114
  }
121
115
  render(width) {
122
- const pad = " ".repeat(this.outputPad);
123
- const contentWidth = Math.max(1, width - this.outputPad - 2);
124
- const lines = [truncateToWidth(`${pad}${this.markdownTheme.codeBlockBorder("╭─ lunr-copy")}`, width, "")];
116
+ if (width <= 0) {
117
+ this.renderedRows = 0;
118
+ return [];
119
+ }
120
+ const horizontalPad = Math.min(this.outputPad, Math.max(0, width - 1));
121
+ const pad = " ".repeat(horizontalPad);
122
+ const contentWidth = Math.max(1, width - horizontalPad * 2);
123
+ const paint = (content) => {
124
+ const line = truncateToWidth(`${pad}${content}`, width, "");
125
+ return theme.bg("userMessageBg", `${line}${" ".repeat(Math.max(0, width - visibleWidth(line)))}`);
126
+ };
127
+ const lines = [paint("")];
125
128
  const payloadLines = this.payload.replace(/\t/g, " ").split("\n");
126
129
  for (const payloadLine of payloadLines) {
127
130
  for (const wrappedLine of wrapTextWithAnsi(payloadLine, contentWidth)) {
128
- lines.push(truncateToWidth(`${pad}${this.markdownTheme.codeBlockBorder("│ ")}${this.markdownTheme.codeBlock(wrappedLine)}`, width, ""));
131
+ lines.push(paint(theme.fg("userMessageText", wrappedLine)));
129
132
  }
130
133
  }
131
- lines.push(truncateToWidth(`${pad}${this.markdownTheme.codeBlockBorder(this.complete ? "╰─" : "╰─ receiving")}`, width, ""));
132
- this.buttonRow = -1;
133
- this.buttonStart = -1;
134
- this.buttonEnd = -1;
135
- if (this.complete) {
136
- const button = "[ Copy ]";
137
- let feedback = "";
138
- if (this.status === "copying")
139
- feedback = theme.fg("dim", " Copying...");
140
- else if (this.status === "copied")
141
- feedback = theme.fg("success", " Copied");
142
- else if (typeof this.status === "object")
143
- feedback = theme.fg("error", ` Copy failed: ${this.status.error}`);
144
- this.buttonRow = lines.length;
145
- this.buttonStart = this.outputPad;
146
- this.buttonEnd = Math.min(width, this.buttonStart + button.length);
147
- lines.push(truncateToWidth(`${pad}${theme.fg("accent", button)}${feedback}`, width, ""));
134
+ if (typeof this.status === "object") {
135
+ for (const wrappedLine of wrapTextWithAnsi(`Copy failed: ${this.status.error}`, contentWidth)) {
136
+ lines.push(paint(theme.fg("error", wrappedLine)));
137
+ }
148
138
  }
139
+ lines.push(paint(""));
140
+ this.renderedRows = lines.length;
149
141
  return lines;
150
142
  }
151
143
  handleClick(localY, width, localX) {
152
144
  this.render(width);
153
145
  if (!this.complete ||
154
146
  this.status === "copying" ||
155
- localX === undefined ||
156
- localY !== this.buttonRow ||
157
- localX < this.buttonStart ||
158
- localX >= this.buttonEnd) {
147
+ localY < 0 ||
148
+ localY >= this.renderedRows ||
149
+ (localX !== undefined && (localX < 0 || localX >= width))) {
159
150
  return false;
160
151
  }
161
152
  this.onCopy();
@@ -1 +1 @@
1
- {"version":3,"file":"copyable-text.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/copyable-text.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MarkdownTheme } from \"@ashx-j/lunr-tui\";\nimport { type Component, truncateToWidth, wrapTextWithAnsi } from \"@ashx-j/lunr-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport type CopyableTextSegment =\n\t| { type: \"markdown\"; text: string }\n\t| { type: \"copyable\"; payload: string; complete: boolean; start: number };\n\ninterface SourceLine {\n\tstart: number;\n\tend: number;\n\ttext: string;\n}\n\ninterface FenceOpening {\n\tmarker: \"`\" | \"~\";\n\tlength: number;\n\tcopyable: boolean;\n}\n\nfunction sourceLines(source: string): SourceLine[] {\n\tconst lines: SourceLine[] = [];\n\tconst pattern = /([^\\r\\n]*)(\\r\\n|\\r|\\n|$)/g;\n\tfor (const match of source.matchAll(pattern)) {\n\t\tconst start = match.index;\n\t\tconst text = match[1];\n\t\tconst newline = match[2];\n\t\tlines.push({ start, end: start + text.length + newline.length, text });\n\t\tif (!newline) break;\n\t}\n\treturn lines;\n}\n\nfunction parseFenceOpening(line: string): FenceOpening | undefined {\n\tconst match = /^( {0,3})(`{3,}|~{3,})(.*)$/.exec(line);\n\tif (!match) return undefined;\n\tconst fence = match[2];\n\tconst info = match[3];\n\tif (fence[0] === \"`\" && info.includes(\"`\")) return undefined;\n\treturn {\n\t\tmarker: fence[0] as \"`\" | \"~\",\n\t\tlength: fence.length,\n\t\tcopyable: info.trim() === \"lunr-copy\",\n\t};\n}\n\nfunction isFenceClosing(line: string, opening: FenceOpening): boolean {\n\tconst match = /^( {0,3})(`+|~+)[ \\t]*$/.exec(line);\n\tif (!match) return false;\n\tconst fence = match[2];\n\treturn fence[0] === opening.marker && fence.length >= opening.length;\n}\n\nfunction payloadEndBeforeClosing(source: string, closingStart: number): number {\n\tif (closingStart >= 2 && source.slice(closingStart - 2, closingStart) === \"\\r\\n\") return closingStart - 2;\n\tif (closingStart >= 1 && (source[closingStart - 1] === \"\\n\" || source[closingStart - 1] === \"\\r\")) {\n\t\treturn closingStart - 1;\n\t}\n\treturn closingStart;\n}\n\nexport function parseCopyableTextSegments(source: string): CopyableTextSegment[] {\n\tconst lines = sourceLines(source);\n\tconst segments: CopyableTextSegment[] = [];\n\tlet emittedThrough = 0;\n\tlet lineIndex = 0;\n\n\twhile (lineIndex < lines.length) {\n\t\tconst openingLine = lines[lineIndex];\n\t\tconst opening = parseFenceOpening(openingLine.text);\n\t\tif (!opening) {\n\t\t\tlineIndex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet closingIndex = -1;\n\t\tfor (let i = lineIndex + 1; i < lines.length; i++) {\n\t\t\tif (isFenceClosing(lines[i].text, opening)) {\n\t\t\t\tclosingIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!opening.copyable) {\n\t\t\tif (closingIndex < 0) break;\n\t\t\tlineIndex = closingIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (openingLine.start > emittedThrough) {\n\t\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough, openingLine.start) });\n\t\t}\n\n\t\tconst payloadStart = openingLine.end;\n\t\tif (closingIndex < 0) {\n\t\t\tsegments.push({\n\t\t\t\ttype: \"copyable\",\n\t\t\t\tpayload: source.slice(payloadStart),\n\t\t\t\tcomplete: false,\n\t\t\t\tstart: openingLine.start,\n\t\t\t});\n\t\t\treturn segments;\n\t\t}\n\n\t\tconst closingLine = lines[closingIndex];\n\t\tsegments.push({\n\t\t\ttype: \"copyable\",\n\t\t\tpayload: source.slice(payloadStart, payloadEndBeforeClosing(source, closingLine.start)),\n\t\t\tcomplete: true,\n\t\t\tstart: openingLine.start,\n\t\t});\n\t\temittedThrough = closingLine.end;\n\t\tlineIndex = closingIndex + 1;\n\t}\n\n\tif (emittedThrough < source.length) {\n\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough) });\n\t}\n\treturn segments;\n}\n\nexport type CopyableTextStatus = \"idle\" | \"copying\" | \"copied\" | { error: string };\n\nexport class CopyableTextBlockComponent implements Component {\n\tprivate buttonRow = -1;\n\tprivate buttonStart = -1;\n\tprivate buttonEnd = -1;\n\tprivate readonly payload: string;\n\tprivate readonly complete: boolean;\n\tprivate readonly outputPad: number;\n\tprivate readonly markdownTheme: MarkdownTheme;\n\tprivate readonly status: CopyableTextStatus;\n\tprivate readonly onCopy: () => void;\n\n\tconstructor(\n\t\tpayload: string,\n\t\tcomplete: boolean,\n\t\toutputPad: number,\n\t\tmarkdownTheme: MarkdownTheme,\n\t\tstatus: CopyableTextStatus,\n\t\tonCopy: () => void,\n\t) {\n\t\tthis.payload = payload;\n\t\tthis.complete = complete;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.status = status;\n\t\tthis.onCopy = onCopy;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.buttonRow = -1;\n\t\tthis.buttonStart = -1;\n\t\tthis.buttonEnd = -1;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst pad = \" \".repeat(this.outputPad);\n\t\tconst contentWidth = Math.max(1, width - this.outputPad - 2);\n\t\tconst lines = [truncateToWidth(`${pad}${this.markdownTheme.codeBlockBorder(\"╭─ lunr-copy\")}`, width, \"\")];\n\t\tconst payloadLines = this.payload.replace(/\\t/g, \" \").split(\"\\n\");\n\n\t\tfor (const payloadLine of payloadLines) {\n\t\t\tfor (const wrappedLine of wrapTextWithAnsi(payloadLine, contentWidth)) {\n\t\t\t\tlines.push(\n\t\t\t\t\ttruncateToWidth(\n\t\t\t\t\t\t`${pad}${this.markdownTheme.codeBlockBorder(\"│ \")}${this.markdownTheme.codeBlock(wrappedLine)}`,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tlines.push(\n\t\t\ttruncateToWidth(\n\t\t\t\t`${pad}${this.markdownTheme.codeBlockBorder(this.complete ? \"╰─\" : \"╰─ receiving\")}`,\n\t\t\t\twidth,\n\t\t\t\t\"\",\n\t\t\t),\n\t\t);\n\n\t\tthis.buttonRow = -1;\n\t\tthis.buttonStart = -1;\n\t\tthis.buttonEnd = -1;\n\t\tif (this.complete) {\n\t\t\tconst button = \"[ Copy ]\";\n\t\t\tlet feedback = \"\";\n\t\t\tif (this.status === \"copying\") feedback = theme.fg(\"dim\", \" Copying...\");\n\t\t\telse if (this.status === \"copied\") feedback = theme.fg(\"success\", \" Copied\");\n\t\t\telse if (typeof this.status === \"object\") feedback = theme.fg(\"error\", ` Copy failed: ${this.status.error}`);\n\t\t\tthis.buttonRow = lines.length;\n\t\t\tthis.buttonStart = this.outputPad;\n\t\t\tthis.buttonEnd = Math.min(width, this.buttonStart + button.length);\n\t\t\tlines.push(truncateToWidth(`${pad}${theme.fg(\"accent\", button)}${feedback}`, width, \"\"));\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleClick(localY: number, width: number, localX?: number): boolean {\n\t\tthis.render(width);\n\t\tif (\n\t\t\t!this.complete ||\n\t\t\tthis.status === \"copying\" ||\n\t\t\tlocalX === undefined ||\n\t\t\tlocalY !== this.buttonRow ||\n\t\t\tlocalX < this.buttonStart ||\n\t\t\tlocalX >= this.buttonEnd\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.onCopy();\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"copyable-text.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/copyable-text.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"@ashx-j/lunr-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport type CopyableTextSegment =\n\t| { type: \"markdown\"; text: string }\n\t| { type: \"copyable\"; payload: string; complete: boolean; start: number };\n\ninterface SourceLine {\n\tstart: number;\n\tend: number;\n\ttext: string;\n}\n\ninterface FenceOpening {\n\tmarker: \"`\" | \"~\";\n\tlength: number;\n\tcopyable: boolean;\n}\n\nfunction sourceLines(source: string): SourceLine[] {\n\tconst lines: SourceLine[] = [];\n\tconst pattern = /([^\\r\\n]*)(\\r\\n|\\r|\\n|$)/g;\n\tfor (const match of source.matchAll(pattern)) {\n\t\tconst start = match.index;\n\t\tconst text = match[1];\n\t\tconst newline = match[2];\n\t\tlines.push({ start, end: start + text.length + newline.length, text });\n\t\tif (!newline) break;\n\t}\n\treturn lines;\n}\n\nfunction parseFenceOpening(line: string): FenceOpening | undefined {\n\tconst match = /^( {0,3})(`{3,}|~{3,})(.*)$/.exec(line);\n\tif (!match) return undefined;\n\tconst fence = match[2];\n\tconst info = match[3];\n\tif (fence[0] === \"`\" && info.includes(\"`\")) return undefined;\n\treturn {\n\t\tmarker: fence[0] as \"`\" | \"~\",\n\t\tlength: fence.length,\n\t\tcopyable: info.trim() === \"lunr-copy\",\n\t};\n}\n\nfunction isFenceClosing(line: string, opening: FenceOpening): boolean {\n\tconst match = /^( {0,3})(`+|~+)[ \\t]*$/.exec(line);\n\tif (!match) return false;\n\tconst fence = match[2];\n\treturn fence[0] === opening.marker && fence.length >= opening.length;\n}\n\nfunction payloadEndBeforeClosing(source: string, closingStart: number): number {\n\tif (closingStart >= 2 && source.slice(closingStart - 2, closingStart) === \"\\r\\n\") return closingStart - 2;\n\tif (closingStart >= 1 && (source[closingStart - 1] === \"\\n\" || source[closingStart - 1] === \"\\r\")) {\n\t\treturn closingStart - 1;\n\t}\n\treturn closingStart;\n}\n\nexport function parseCopyableTextSegments(source: string): CopyableTextSegment[] {\n\tconst lines = sourceLines(source);\n\tconst segments: CopyableTextSegment[] = [];\n\tlet emittedThrough = 0;\n\tlet lineIndex = 0;\n\n\twhile (lineIndex < lines.length) {\n\t\tconst openingLine = lines[lineIndex];\n\t\tconst opening = parseFenceOpening(openingLine.text);\n\t\tif (!opening) {\n\t\t\tlineIndex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet closingIndex = -1;\n\t\tfor (let i = lineIndex + 1; i < lines.length; i++) {\n\t\t\tif (isFenceClosing(lines[i].text, opening)) {\n\t\t\t\tclosingIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!opening.copyable) {\n\t\t\tif (closingIndex < 0) break;\n\t\t\tlineIndex = closingIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (openingLine.start > emittedThrough) {\n\t\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough, openingLine.start) });\n\t\t}\n\n\t\tconst payloadStart = openingLine.end;\n\t\tif (closingIndex < 0) {\n\t\t\tsegments.push({\n\t\t\t\ttype: \"copyable\",\n\t\t\t\tpayload: source.slice(payloadStart),\n\t\t\t\tcomplete: false,\n\t\t\t\tstart: openingLine.start,\n\t\t\t});\n\t\t\treturn segments;\n\t\t}\n\n\t\tconst closingLine = lines[closingIndex];\n\t\tsegments.push({\n\t\t\ttype: \"copyable\",\n\t\t\tpayload: source.slice(payloadStart, payloadEndBeforeClosing(source, closingLine.start)),\n\t\t\tcomplete: true,\n\t\t\tstart: openingLine.start,\n\t\t});\n\t\temittedThrough = closingLine.end;\n\t\tlineIndex = closingIndex + 1;\n\t}\n\n\tif (emittedThrough < source.length) {\n\t\tsegments.push({ type: \"markdown\", text: source.slice(emittedThrough) });\n\t}\n\treturn segments;\n}\n\nexport type CopyableTextStatus = \"idle\" | \"copying\" | \"copied\" | { error: string };\n\nexport class CopyableTextBlockComponent implements Component {\n\tprivate renderedRows = 0;\n\tprivate readonly payload: string;\n\tprivate readonly complete: boolean;\n\tprivate readonly outputPad: number;\n\tprivate readonly status: CopyableTextStatus;\n\tprivate readonly onCopy: () => void;\n\n\tconstructor(payload: string, complete: boolean, outputPad: number, status: CopyableTextStatus, onCopy: () => void) {\n\t\tthis.payload = payload;\n\t\tthis.complete = complete;\n\t\tthis.outputPad = outputPad;\n\t\tthis.status = status;\n\t\tthis.onCopy = onCopy;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.renderedRows = 0;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width <= 0) {\n\t\t\tthis.renderedRows = 0;\n\t\t\treturn [];\n\t\t}\n\n\t\tconst horizontalPad = Math.min(this.outputPad, Math.max(0, width - 1));\n\t\tconst pad = \" \".repeat(horizontalPad);\n\t\tconst contentWidth = Math.max(1, width - horizontalPad * 2);\n\t\tconst paint = (content: string): string => {\n\t\t\tconst line = truncateToWidth(`${pad}${content}`, width, \"\");\n\t\t\treturn theme.bg(\"userMessageBg\", `${line}${\" \".repeat(Math.max(0, width - visibleWidth(line)))}`);\n\t\t};\n\t\tconst lines = [paint(\"\")];\n\t\tconst payloadLines = this.payload.replace(/\\t/g, \" \").split(\"\\n\");\n\n\t\tfor (const payloadLine of payloadLines) {\n\t\t\tfor (const wrappedLine of wrapTextWithAnsi(payloadLine, contentWidth)) {\n\t\t\t\tlines.push(paint(theme.fg(\"userMessageText\", wrappedLine)));\n\t\t\t}\n\t\t}\n\n\t\tif (typeof this.status === \"object\") {\n\t\t\tfor (const wrappedLine of wrapTextWithAnsi(`Copy failed: ${this.status.error}`, contentWidth)) {\n\t\t\t\tlines.push(paint(theme.fg(\"error\", wrappedLine)));\n\t\t\t}\n\t\t}\n\t\tlines.push(paint(\"\"));\n\t\tthis.renderedRows = lines.length;\n\t\treturn lines;\n\t}\n\n\thandleClick(localY: number, width: number, localX?: number): boolean {\n\t\tthis.render(width);\n\t\tif (\n\t\t\t!this.complete ||\n\t\t\tthis.status === \"copying\" ||\n\t\t\tlocalY < 0 ||\n\t\t\tlocalY >= this.renderedRows ||\n\t\t\t(localX !== undefined && (localX < 0 || localX >= width))\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.onCopy();\n\t\treturn true;\n\t}\n}\n"]}
@@ -2,7 +2,7 @@ import type { ThinkingLevel } from "@ashx-j/lunr-agent";
2
2
  import type { Transport } from "@ashx-j/lunr-ai";
3
3
  import { type Component, Container, SettingsList } from "@ashx-j/lunr-tui";
4
4
  import type { SearchCuratorSetting } from "../../../core/search-curator.ts";
5
- import { type DefaultPermissionMode, type DefaultProjectTrust, type ModelInstructionsSettings, type ModelTierName, type ModelTiersSettings, type RollbackCapture, type RollbackScope, type SkillTagCharacter } from "../../../core/settings-manager.ts";
5
+ import { type DefaultPermissionMode, type DefaultProjectTrust, type ModelInstructionsSettings, type ModelTierName, type ModelTiersSettings, type ReasoningDisplay, type RollbackCapture, type RollbackScope, type SkillTagCharacter } from "../../../core/settings-manager.ts";
6
6
  import { type SubagentSpinnerName } from "../../../core/subagent-spinner.ts";
7
7
  import { type TerminalTheme } from "../theme/theme.ts";
8
8
  export interface SettingsConfig {
@@ -24,6 +24,7 @@ export interface SettingsConfig {
24
24
  availableThemes: string[];
25
25
  hideThinkingBlock: boolean;
26
26
  thinkingCollapse: boolean;
27
+ reasoningDisplay: ReasoningDisplay;
27
28
  showCacheMissNotices: boolean;
28
29
  /** Display value; unset settings render as "short". */
29
30
  cacheRetention: "none" | "short" | "long";
@@ -87,6 +88,7 @@ export interface SettingsCallbacks {
87
88
  onThemePreview?: (theme: string) => void;
88
89
  onHideThinkingBlockChange: (hidden: boolean) => void;
89
90
  onThinkingCollapseChange: (collapse: boolean) => void;
91
+ onReasoningDisplayChange: (display: ReasoningDisplay) => void;
90
92
  onShowCacheMissNoticesChange: (shown: boolean) => void;
91
93
  onCacheRetentionChange: (retention: "none" | "short" | "long") => void;
92
94
  onDoubleEscapeActionChange: (action: "fork" | "tree" | "none") => void;