@vybestack/llxprt-ui 0.7.0-nightly.251211.5750c518a

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 (123) hide show
  1. package/PLAN-messages.md +681 -0
  2. package/PLAN.md +47 -0
  3. package/README.md +25 -0
  4. package/bun.lock +1024 -0
  5. package/dev-docs/ARCHITECTURE.md +178 -0
  6. package/dev-docs/CODE_ORGANIZATION.md +232 -0
  7. package/dev-docs/STANDARDS.md +235 -0
  8. package/dev-docs/UI_DESIGN.md +425 -0
  9. package/eslint.config.cjs +194 -0
  10. package/images/nui.png +0 -0
  11. package/llxprt.png +0 -0
  12. package/llxprt.svg +128 -0
  13. package/package.json +66 -0
  14. package/scripts/check-limits.ts +177 -0
  15. package/scripts/start.js +71 -0
  16. package/src/app.tsx +599 -0
  17. package/src/bootstrap.tsx +23 -0
  18. package/src/commands/AuthCommand.tsx +80 -0
  19. package/src/commands/ModelCommand.tsx +102 -0
  20. package/src/commands/ProviderCommand.tsx +103 -0
  21. package/src/commands/ThemeCommand.tsx +71 -0
  22. package/src/features/chat/history.ts +178 -0
  23. package/src/features/chat/index.ts +3 -0
  24. package/src/features/chat/persistentHistory.ts +102 -0
  25. package/src/features/chat/responder.ts +217 -0
  26. package/src/features/completion/completions.ts +161 -0
  27. package/src/features/completion/index.ts +3 -0
  28. package/src/features/completion/slash.test.ts +82 -0
  29. package/src/features/completion/slash.ts +248 -0
  30. package/src/features/completion/suggestions.test.ts +51 -0
  31. package/src/features/completion/suggestions.ts +112 -0
  32. package/src/features/config/configSession.test.ts +189 -0
  33. package/src/features/config/configSession.ts +179 -0
  34. package/src/features/config/index.ts +4 -0
  35. package/src/features/config/llxprtAdapter.integration.test.ts +202 -0
  36. package/src/features/config/llxprtAdapter.test.ts +139 -0
  37. package/src/features/config/llxprtAdapter.ts +257 -0
  38. package/src/features/config/llxprtCommands.test.ts +40 -0
  39. package/src/features/config/llxprtCommands.ts +35 -0
  40. package/src/features/config/llxprtConfig.test.ts +261 -0
  41. package/src/features/config/llxprtConfig.ts +418 -0
  42. package/src/features/theme/index.ts +2 -0
  43. package/src/features/theme/theme.test.ts +51 -0
  44. package/src/features/theme/theme.ts +105 -0
  45. package/src/features/theme/themeManager.ts +84 -0
  46. package/src/hooks/useAppCommands.ts +129 -0
  47. package/src/hooks/useApprovalKeyboard.ts +156 -0
  48. package/src/hooks/useChatStore.test.ts +112 -0
  49. package/src/hooks/useChatStore.ts +252 -0
  50. package/src/hooks/useInputManager.ts +99 -0
  51. package/src/hooks/useKeyboardHandlers.ts +130 -0
  52. package/src/hooks/useListNavigation.test.ts +166 -0
  53. package/src/hooks/useListNavigation.ts +62 -0
  54. package/src/hooks/usePersistentHistory.ts +94 -0
  55. package/src/hooks/useScrollManagement.ts +107 -0
  56. package/src/hooks/useSelectionClipboard.ts +48 -0
  57. package/src/hooks/useSessionManager.test.ts +85 -0
  58. package/src/hooks/useSessionManager.ts +101 -0
  59. package/src/hooks/useStreamingLifecycle.ts +71 -0
  60. package/src/hooks/useStreamingResponder.ts +401 -0
  61. package/src/hooks/useSuggestionSetup.ts +23 -0
  62. package/src/hooks/useToolApproval.test.ts +140 -0
  63. package/src/hooks/useToolApproval.ts +264 -0
  64. package/src/hooks/useToolScheduler.ts +432 -0
  65. package/src/index.ts +3 -0
  66. package/src/jsx.d.ts +11 -0
  67. package/src/lib/clipboard.ts +18 -0
  68. package/src/lib/logger.ts +107 -0
  69. package/src/lib/random.ts +5 -0
  70. package/src/main.tsx +13 -0
  71. package/src/test/mockTheme.ts +51 -0
  72. package/src/types/events.ts +87 -0
  73. package/src/types.ts +13 -0
  74. package/src/ui/components/ChatLayout.tsx +694 -0
  75. package/src/ui/components/CommandComponents.tsx +74 -0
  76. package/src/ui/components/DiffViewer.tsx +306 -0
  77. package/src/ui/components/FilterInput.test.ts +69 -0
  78. package/src/ui/components/FilterInput.tsx +62 -0
  79. package/src/ui/components/HeaderBar.tsx +137 -0
  80. package/src/ui/components/RadioSelect.test.ts +140 -0
  81. package/src/ui/components/RadioSelect.tsx +88 -0
  82. package/src/ui/components/SelectableList.test.ts +83 -0
  83. package/src/ui/components/SelectableList.tsx +35 -0
  84. package/src/ui/components/StatusBar.tsx +45 -0
  85. package/src/ui/components/SuggestionPanel.tsx +102 -0
  86. package/src/ui/components/messages/ModelMessage.tsx +14 -0
  87. package/src/ui/components/messages/SystemMessage.tsx +29 -0
  88. package/src/ui/components/messages/ThinkingMessage.tsx +14 -0
  89. package/src/ui/components/messages/UserMessage.tsx +26 -0
  90. package/src/ui/components/messages/index.ts +15 -0
  91. package/src/ui/components/messages/renderMessage.test.ts +49 -0
  92. package/src/ui/components/messages/renderMessage.tsx +43 -0
  93. package/src/ui/components/messages/types.test.ts +24 -0
  94. package/src/ui/components/messages/types.ts +36 -0
  95. package/src/ui/modals/AuthModal.tsx +106 -0
  96. package/src/ui/modals/ModalShell.tsx +60 -0
  97. package/src/ui/modals/SearchSelectModal.tsx +236 -0
  98. package/src/ui/modals/ThemeModal.tsx +204 -0
  99. package/src/ui/modals/ToolApprovalModal.test.ts +206 -0
  100. package/src/ui/modals/ToolApprovalModal.tsx +282 -0
  101. package/src/ui/modals/index.ts +20 -0
  102. package/src/ui/modals/modals.test.ts +26 -0
  103. package/src/ui/modals/types.ts +19 -0
  104. package/src/uicontext/Command.tsx +102 -0
  105. package/src/uicontext/Dialog.tsx +65 -0
  106. package/src/uicontext/index.ts +2 -0
  107. package/themes/ansi-light.json +59 -0
  108. package/themes/ansi.json +59 -0
  109. package/themes/atom-one-dark.json +59 -0
  110. package/themes/ayu-light.json +59 -0
  111. package/themes/ayu.json +59 -0
  112. package/themes/default-light.json +59 -0
  113. package/themes/default.json +59 -0
  114. package/themes/dracula.json +59 -0
  115. package/themes/github-dark.json +59 -0
  116. package/themes/github-light.json +59 -0
  117. package/themes/googlecode.json +59 -0
  118. package/themes/green-screen.json +59 -0
  119. package/themes/no-color.json +59 -0
  120. package/themes/shades-of-purple.json +59 -0
  121. package/themes/xcode.json +59 -0
  122. package/tsconfig.json +28 -0
  123. package/vitest.config.ts +10 -0
package/llxprt.svg ADDED
@@ -0,0 +1,128 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
3
+ viewBox="0 0 415 260" >
4
+ <style type="text/css">
5
+ .st0{fill:none;stroke:#000000;stroke-width:5.1877;}
6
+ .st1{fill:none;stroke:#C0C0C0;stroke-width:9.8156;}
7
+ .st2{fill:url(#SVGID_1_);}
8
+ .st3{opacity:0.6;fill:#FFFFFF;}
9
+ .st4{opacity:0.4;fill:#FFFFFF;}
10
+ </style>
11
+ <circle class="st0" cx="246.09" cy="75.4" r="70.4"/>
12
+ <circle class="st1" cx="246.09" cy="75.4" r="63.02"/>
13
+ <radialGradient id="SVGID_1_" cx="246.0865" cy="75.5194" r="65.8884" gradientUnits="userSpaceOnUse">
14
+ <stop offset="0" style="stop-color:#FFFF00"/>
15
+ <stop offset="0.6441" style="stop-color:#FF0A00"/>
16
+ <stop offset="0.9927" style="stop-color:#FF0A00"/>
17
+ </radialGradient>
18
+ <circle class="st2" cx="246.09" cy="75.4" r="52"/>
19
+ <circle class="st3" cx="231.23" cy="56.83" r="7.43"/>
20
+ <circle class="st4" cx="260.94" cy="49.4" r="4.46"/>
21
+ <path d="M-0.38,122.22l21.99-1.94l11-0.95l5.5-0.46c1.81-0.16,3.59-0.36,5.37-0.71c3.54-0.65,6.99-1.71,10.31-3.08
22
+ c1.66-0.69,3.28-1.46,4.87-2.3c1.59-0.84,3.12-1.77,4.77-2.69c6.56-3.64,13.61-6.41,20.87-8.29c7.25-1.94,14.72-3.01,22.21-3.42
23
+ l2.81-0.14c0.94-0.03,1.87-0.02,2.81-0.03l2.81-0.01c0.94,0.01,1.89,0.09,2.84,0.13l2.85,0.15c0.95,0.07,1.89,0.22,2.83,0.33
24
+ l2.83,0.36l2.81,0.54c7.48,1.48,14.74,4.08,21.49,7.52c6.75,3.43,13.09,7.51,19.18,11.68c3.05,2.08,6.06,4.15,9.08,6.13l4.6,2.9
25
+ c1.61,0.99,3.18,2,4.73,3.02c6.2,4.08,12.18,8.13,18.45,11.54c6.24,3.44,12.77,6.14,19.54,7.91c6.77,1.77,13.75,2.68,20.79,2.75
26
+ l5.4-0.13c1.83-0.03,3.21-0.1,4.94-0.38c3.37-0.52,6.92-1.36,10.46-2.18c7.1-1.69,14.31-3.49,21.59-5.02
27
+ c1.82-0.39,3.65-0.75,5.47-1.12c0.91-0.18,1.91-0.33,2.86-0.5l1.44-0.24l1.47-0.17c3.91-0.47,7.96-0.67,12.17-0.08
28
+ c4.17,0.59,8.65,2.05,12.35,5.06c1.86,1.48,3.37,3.34,4.62,5.28c1.22,1.97,2.06,4.06,2.73,6.13l-6.04-3.02
29
+ c1.28-0.46,2.32-0.78,3.48-1.11c1.13-0.32,2.26-0.62,3.4-0.88c2.28-0.53,4.58-0.96,6.92-1.27c4.67-0.61,9.51-0.78,14.44-0.02
30
+ c4.9,0.71,9.98,2.54,14.24,5.85c2.13,1.65,3.94,3.69,5.44,5.88c1.54,2.19,2.56,4.59,3.47,6.98l-4.41-3.2
31
+ c0.83,0.02,1.4,0.06,2.07,0.11c0.65,0.06,1.29,0.12,1.93,0.2c1.27,0.16,2.54,0.36,3.8,0.62c2.52,0.51,5.03,1.2,7.5,2.18
32
+ c2.47,0.98,4.91,2.21,7.19,3.87c2.27,1.65,4.38,3.73,6.04,6.19c1.65,2.47,2.76,5.3,3.31,8.14c0.13,0.71,0.28,1.4,0.33,2.17
33
+ l0.1,1.12c0.01,0.2,0.04,0.34,0.04,0.59l-0.02,0.75c-0.09,1.68-0.44,3.35-1.08,4.94c-0.64,1.59-1.58,3.09-2.71,4.36
34
+ c-1.13,1.29-2.47,2.27-3.82,3.12c-2.74,1.6-5.57,2.36-8.27,2.81l3.93-5.53c0.1,0.6,0.11,0.86,0.15,1.26
35
+ c0.02,0.36,0.05,0.72,0.05,1.07c0.01,0.71-0.01,1.41-0.09,2.12c-0.13,1.41-0.42,2.85-0.96,4.28c-0.97,2.86-3.14,5.57-5.73,7.24
36
+ c-0.64,0.43-1.32,0.75-1.98,1.1c-0.65,0.31-1.3,0.56-1.96,0.78c-1.32,0.44-2.65,0.74-3.96,0.91c-0.66,0.09-1.31,0.15-1.96,0.18
37
+ c-0.35,0.02-0.6,0.02-0.86,0.02l-0.8,0.01l-3.21,0.04c-2.17,0-4.22,0.1-6.29,0.19c-2.07,0.07-4.14,0.28-6.21,0.41
38
+ c-2.07,0.12-4.14,0.4-6.21,0.59c-1.03,0.11-2.07,0.2-3.1,0.33l-3.09,0.43c-2.06,0.3-4.13,0.53-6.18,0.89l-6.16,1.06l-12.47,2.37
39
+ c-8.28,1.61-16.52,3.36-24.72,5.3c-16.4,3.89-32.67,8.47-48.82,13.47l-12.18,3.81l-6.13,1.77c-2.05,0.6-4.12,1.2-6.22,1.76
40
+ c-4.2,1.12-8.52,2.08-12.94,2.68c-4.42,0.6-8.95,0.73-13.45,0.45l-3.37-0.32c-1.12-0.15-2.23-0.37-3.34-0.55l-1.67-0.29
41
+ l-1.64-0.42l-3.27-0.85c-4.26-1.4-8.46-3.01-12.33-5.17l-2.93-1.57l-2.75-1.6l-5.49-3.18c-3.67-2.1-7.35-4.15-11.06-6.16
42
+ c-7.43-4-14.95-7.81-22.6-11.36c-7.65-3.53-15.43-6.8-23.31-9.78c-15.77-5.95-32.08-10.53-48.78-12.98
43
+ c-8.35-1.21-16.79-1.81-25.24-1.69c-8.45,0.11-16.92,0.99-25.22,2.82c8.19-2.27,16.65-3.62,25.16-4.18
44
+ c8.52-0.55,17.09-0.29,25.6,0.56c17.04,1.68,33.76,5.85,49.97,11.26c16.23,5.43,31.93,12.36,47.2,20.03
45
+ c3.81,1.93,7.6,3.9,11.37,5.91l5.63,3.04l2.79,1.54l2.72,1.38c3.59,1.91,7.39,3.25,11.21,4.44l2.91,0.69l1.46,0.34l1.48,0.22
46
+ c0.99,0.14,1.96,0.32,2.95,0.43l2.98,0.22c3.98,0.16,7.97-0.02,11.95-0.65c3.98-0.63,7.95-1.59,11.93-2.74
47
+ c1.99-0.57,3.99-1.2,6-1.83l6.07-1.89c4.02-1.33,7.99-2.69,12.07-3.98c16.22-5.24,32.61-10.08,49.21-14.24
48
+ c8.3-2.07,16.65-3.96,25.02-5.69c4.18-0.86,8.37-1.66,12.55-2.46l6.39-1.13c2.13-0.38,4.28-0.63,6.42-0.95l3.21-0.46
49
+ c1.07-0.14,2.15-0.24,3.23-0.36c2.16-0.21,4.3-0.51,6.46-0.65c2.16-0.15,4.32-0.37,6.49-0.45c2.18-0.11,4.36-0.22,6.44-0.23
50
+ l3.16-0.05l0.79-0.01c0.26,0,0.55-0.01,0.73-0.02c0.41-0.02,0.81-0.06,1.2-0.12c0.79-0.11,1.54-0.28,2.23-0.52
51
+ c0.34-0.12,0.69-0.25,0.99-0.4c0.26-0.17,0.56-0.28,0.8-0.45c0.46-0.34,0.9-0.66,1.2-1.11c0.19-0.18,0.29-0.46,0.46-0.67
52
+ c0.1-0.27,0.27-0.5,0.35-0.81c0.22-0.56,0.35-1.22,0.42-1.92c0.04-0.35,0.05-0.71,0.04-1.06c0-0.18-0.02-0.35-0.02-0.52
53
+ c-0.01-0.13-0.04-0.39-0.03-0.32l3.93-5.53c1.88-0.32,3.61-0.85,4.89-1.62c1.27-0.79,2.07-1.69,2.52-2.82
54
+ c0.23-0.56,0.36-1.21,0.39-1.85c0-0.05,0-0.08,0-0.12c0-0.04-0.02-0.19-0.03-0.28l-0.07-0.62c-0.02-0.4-0.13-0.85-0.2-1.28
55
+ c-0.35-1.73-0.99-3.3-1.91-4.72c-1.86-2.82-5.01-5.03-8.74-6.49c-1.86-0.74-3.85-1.31-5.89-1.73c-1.02-0.21-2.06-0.38-3.09-0.51
56
+ c-0.52-0.07-1.03-0.12-1.55-0.17c-0.48-0.04-1.08-0.08-1.41-0.09l-3.21-0.1l-1.2-3.1c-0.66-1.7-1.34-3.38-2.34-4.78
57
+ c-0.98-1.42-2.09-2.71-3.44-3.76c-2.68-2.09-6.08-3.44-9.85-3.99c-3.75-0.6-7.78-0.51-11.8,0c-2.01,0.26-4.03,0.62-6.02,1.08
58
+ c-1,0.23-1.99,0.48-2.97,0.76c-0.96,0.26-2.01,0.59-2.8,0.87l-4.54,1.6l-1.5-4.62c-0.46-1.42-1-2.77-1.71-3.93
59
+ c-0.74-1.13-1.56-2.18-2.59-2.99c-2.03-1.66-4.76-2.67-7.83-3.16c-3.08-0.48-6.45-0.39-9.83-0.02l-1.27,0.13l-1.28,0.2
60
+ c-0.86,0.14-1.69,0.25-2.58,0.42l-5.35,1.02c-7.13,1.41-14.23,3.08-21.46,4.71c-3.63,0.8-7.26,1.62-11.17,2.18
61
+ c-1.9,0.31-4.2,0.41-6.05,0.4l-5.63,0.06c-7.66-0.19-15.38-1.22-22.79-3.36c-7.42-2.11-14.52-5.24-21.08-9.03
62
+ c-6.59-3.76-12.72-8.11-18.72-12.23c-1.5-1.04-3.01-2.04-4.51-3.01l-4.67-3.08c-3.09-2.11-6.1-4.27-9.08-6.4
63
+ c-5.96-4.27-11.89-8.37-18.17-11.77c-6.26-3.42-12.92-6.01-19.83-7.59c-6.9-1.61-14.05-2-21.29-1.86
64
+ c-7.21,0.14-14.42,0.9-21.44,2.51c-7.04,1.55-13.89,3.96-20.32,7.23c-1.59,0.81-3.24,1.73-4.95,2.53
65
+ c-1.7,0.81-3.43,1.54-5.2,2.19c-3.54,1.29-7.21,2.24-10.93,2.75c-1.85,0.28-3.74,0.41-5.6,0.49l-5.51,0.22l-11.03,0.41
66
+ L-0.38,122.22z"
67
+ fill="#C0C0C0"
68
+ stroke="#000000"
69
+ stroke-width="1"
70
+ paint-order="stroke"
71
+ />
72
+
73
+ <path d="M255.71,153.08c3.96,2.49,7.69,5.02,11.43,7.67c3.73,2.63,7.39,5.39,10.98,8.26c3.59,2.86,7.09,5.88,10.43,9.15
74
+ c1.69,1.6,3.28,3.36,4.87,5.13l2.27,2.82c0.72,0.98,1.37,2.02,2.05,3.03c2.62,4.01,4.76,8.74,5.29,13.98
75
+ c0.26,2.62,0.03,5.41-0.91,8.02l-0.39,0.97l-0.2,0.48c-0.08,0.17-0.1,0.27-0.3,0.63c-0.46,0.78-0.9,1.33-1.4,1.88
76
+ c-0.99,1.08-2.1,1.98-3.31,2.68c-2.41,1.44-5.08,2.14-7.65,2.33c-2.57,0.18-5.08-0.04-7.46-0.52c-1.2-0.22-2.35-0.58-3.51-0.86
77
+ c-1.03-0.27-2.05-0.55-3.1-0.81l-3.19-0.66l-3.26-0.55c-8.77-1.32-17.81-2.18-26.73-3.94c-4.47-0.83-8.89-1.95-13.25-3.26
78
+ l-3.25-1.05c-1.09-0.34-2.14-0.8-3.21-1.19c-2.15-0.76-4.21-1.76-6.29-2.68c-2.04-0.98-4.07-2.11-6.03-3.13
79
+ c-1.93-1.04-3.97-1.96-6.01-2.85c-4.1-1.76-8.29-3.34-12.53-4.81c-8.48-2.9-17.1-5.47-25.95-7.06c8.91,1.2,17.68,3.38,26.32,5.92
80
+ c4.32,1.29,8.6,2.69,12.84,4.29c2.11,0.81,4.21,1.65,6.29,2.65c2.07,0.96,4.01,1.94,6.06,2.81c2.06,0.81,4.1,1.68,6.22,2.33
81
+ c1.06,0.33,2.09,0.73,3.16,1.01l3.2,0.88c4.3,1.08,8.64,1.98,13.04,2.59c8.79,1.34,17.7,1.78,26.75,2.73l3.41,0.42l3.44,0.55
82
+ c1.15,0.22,2.31,0.49,3.46,0.74c1.03,0.19,2.04,0.46,3.06,0.6c2.03,0.31,4.05,0.37,5.95,0.16c1.9-0.22,3.65-0.82,5.07-1.76
83
+ c0.72-0.45,1.34-1.02,1.84-1.62c0.24-0.29,0.48-0.64,0.58-0.84c-0.05,0.11,0.01-0.05,0.04-0.15l0.1-0.3l0.22-0.6
84
+ c0.51-1.66,0.6-3.46,0.33-5.29c-0.26-1.84-0.86-3.7-1.66-5.51c-0.41-0.9-0.86-1.8-1.38-2.66c-0.51-0.87-1.04-1.69-1.7-2.58
85
+ c-2.27-3.39-5.3-6.37-8.52-9.25c-3.21-2.87-6.65-5.59-10.21-8.17c-3.55-2.59-7.19-5.08-10.91-7.47
86
+ c-3.7-2.38-7.52-4.73-11.27-6.86L255.71,153.08z"
87
+ fill="#C0C0C0"
88
+ stroke="#000000"
89
+ stroke-width="1"
90
+ paint-order="stroke"
91
+ />
92
+
93
+ <path d="M385.35,207.8c-0.01-0.01,0-0.02-0.02-0.05l-0.15-0.21c-0.1-0.14-0.18-0.28-0.3-0.43l-0.77-0.93
94
+ c-0.29-0.31-0.6-0.61-0.9-0.91c-0.3-0.31-0.59-0.62-0.95-0.9c-0.7-0.56-1.33-1.19-2.09-1.7l-2.26-1.58l-2.44-1.4
95
+ c-0.41-0.23-0.8-0.49-1.23-0.69l-1.3-0.6l-2.6-1.2c-0.89-0.37-1.81-0.66-2.72-1l-2.74-0.99l-2.83-0.77l-2.84-0.77
96
+ c-0.94-0.28-1.93-0.39-2.9-0.6c-1.95-0.34-3.88-0.79-5.85-1.04l-5.94-0.68c-1.98-0.29-3.99-0.27-5.99-0.4
97
+ c-2-0.08-4.01-0.23-6.02-0.24l-6.04,0.09c-2.01,0.06-4.04-0.01-6.05,0.19l-6.05,0.44l-3.03,0.22l-1.52,0.12l-1.51,0.19
98
+ l-12.08,1.51l11.92-2.59l1.49-0.32l1.51-0.25l3.01-0.49l6.04-0.99c2.01-0.38,4.05-0.51,6.08-0.75l6.11-0.64
99
+ c2.04-0.17,4.1-0.2,6.15-0.31c2.06-0.06,4.11-0.26,6.18-0.15l6.21,0.15c2.07,0.08,4.14,0.37,6.22,0.54
100
+ c1.04,0.12,2.08,0.15,3.11,0.36l3.1,0.55l3.11,0.55l3.08,0.8c1.03,0.28,2.06,0.52,3.08,0.84l3.04,1.08l1.52,0.55
101
+ c0.51,0.19,0.99,0.44,1.49,0.66l2.98,1.37l2.89,1.66c0.97,0.54,1.87,1.26,2.82,1.89c0.47,0.31,0.92,0.69,1.36,1.07
102
+ c0.45,0.38,0.9,0.74,1.34,1.14l1.3,1.3c0.22,0.23,0.44,0.5,0.65,0.75l0.32,0.39l0.41,0.58L385.35,207.8z"
103
+ fill="#C0C0C0"
104
+ stroke="#000000"
105
+ stroke-width="1"
106
+ paint-order="stroke"
107
+ />
108
+
109
+ <path d="M380,178.69c-7.36,0.06-14.78,0.22-22.17,0.46c-7.4,0.24-14.79,0.55-22.18,0.98c-7.38,0.46-14.77,0.99-22.12,1.79
110
+ c-3.67,0.44-7.35,0.87-10.98,1.52c-3.65,0.59-7.25,1.42-10.77,2.63c3.37-1.54,6.93-2.74,10.53-3.69
111
+ c3.59-1.01,7.23-1.8,10.88-2.61c7.3-1.52,14.64-2.79,22-3.97c7.36-1.16,14.74-2.2,22.12-3.17c7.39-0.97,14.77-1.85,22.22-2.65
112
+ L380,178.69z"
113
+ fill="#C0C0C0"
114
+ stroke="#000000"
115
+ stroke-width="1"
116
+ paint-order="stroke"/>
117
+
118
+ <path d="M331.96,164.72l-6.35,2.25l-0.48,0.17l-0.12,0.02c-3.87,0.53-7.7,1-11.55,1.46c-3.85,0.46-7.7,0.87-11.56,1.26
119
+ c-3.85,0.39-7.72,0.71-11.58,0.97c-3.86,0.25-7.74,0.45-11.61,0.31c3.82-0.54,7.56-1.42,11.29-2.34
120
+ c3.73-0.93,7.44-1.92,11.13-2.98c3.7-1.05,7.38-2.13,11.06-3.25c3.67-1.12,7.35-2.26,10.98-3.44l-0.6,0.19l6.16-2.73
121
+ L331.96,164.72z"
122
+ fill="#C0C0C0"
123
+ stroke="#000000"
124
+ stroke-width="1"
125
+ paint-order="stroke"
126
+ />
127
+
128
+ </svg>
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@vybestack/llxprt-ui",
3
+ "version": "0.7.0-nightly.251211.5750c518a",
4
+ "description": "Experimental terminal UI for llxprt-code",
5
+ "type": "module",
6
+ "main": "src/index.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./src/index.ts",
10
+ "bun": "./src/index.ts"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "echo 'UI package uses bun runtime - no build required'",
15
+ "dev": "bun run src/main.tsx",
16
+ "start": "bun run src/main.tsx",
17
+ "lint": "bunx eslint \"src/**/*.{ts,tsx}\" \"scripts/**/*.ts\"",
18
+ "test": "bunx vitest run",
19
+ "test:ci": "bunx vitest run",
20
+ "test:coverage": "bunx vitest run --coverage",
21
+ "check:limits": "bun run scripts/check-limits.ts",
22
+ "check": "bun run lint && bun run test && bun run check:limits",
23
+ "typecheck": "bunx tsc --noEmit"
24
+ },
25
+ "keywords": [
26
+ "llxprt",
27
+ "terminal-ui",
28
+ "opentui",
29
+ "experimental"
30
+ ],
31
+ "author": "Vybestack",
32
+ "license": "ISC",
33
+ "engines": {
34
+ "node": ">=20",
35
+ "bun": ">=1.2.0"
36
+ },
37
+ "dependencies": {
38
+ "@vybestack/opentui-core": "^0.1.61",
39
+ "@vybestack/opentui-react": "^0.1.61",
40
+ "clipboardy": "^4.0.0",
41
+ "react": "^19.2.1"
42
+ },
43
+ "peerDependencies": {
44
+ "@vybestack/llxprt-code-core": "^0.7.0-nightly.251211.5750c518a"
45
+ },
46
+ "devDependencies": {
47
+ "@eslint/js": "^9.39.1",
48
+ "@testing-library/react": "^16.3.0",
49
+ "@types/bun": "^1.3.4",
50
+ "@types/node": "^24.10.1",
51
+ "@types/react": "^19.2.7",
52
+ "@typescript-eslint/eslint-plugin": "^8.48.1",
53
+ "@typescript-eslint/parser": "^8.48.1",
54
+ "@vitest/eslint-plugin": "^1.5.1",
55
+ "eslint": "^9.39.1",
56
+ "eslint-plugin-eslint-comments": "^3.2.0",
57
+ "eslint-plugin-react": "^7.37.5",
58
+ "eslint-plugin-react-hooks": "^7.0.1",
59
+ "eslint-plugin-sonarjs": "^3.0.5",
60
+ "globals": "^16.5.0",
61
+ "happy-dom": "^18.0.1",
62
+ "tsx": "^4.21.0",
63
+ "typescript": "^5.9.3",
64
+ "vitest": "^4.0.15"
65
+ }
66
+ }
@@ -0,0 +1,177 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import ts from 'typescript';
4
+ import { getLogger } from '../src/lib/logger';
5
+
6
+ type ViolationLevel = 'warn' | 'error';
7
+
8
+ interface Violation {
9
+ level: ViolationLevel;
10
+ message: string;
11
+ }
12
+
13
+ const FILE_WARN_LINES = 800;
14
+ const FILE_ERROR_LINES = 1200;
15
+ const FUNCTION_WARN_LINES = 80;
16
+ const FUNCTION_ERROR_LINES = 120;
17
+
18
+ const projectRoot = path.resolve(new URL('.', import.meta.url).pathname, '..');
19
+
20
+ const sourceRoots = [
21
+ path.join(projectRoot, '..', 'src'),
22
+ path.join(projectRoot, '..', 'scripts'),
23
+ ];
24
+
25
+ const violations: Violation[] = [];
26
+
27
+ for (const root of sourceRoots) {
28
+ for (const filePath of collectSourceFiles(root)) {
29
+ checkFileLimits(filePath);
30
+ }
31
+ }
32
+
33
+ reportViolations(violations);
34
+
35
+ function collectSourceFiles(root: string): string[] {
36
+ if (!fs.existsSync(root)) {
37
+ return [];
38
+ }
39
+
40
+ const entries = fs.readdirSync(root, { withFileTypes: true });
41
+ const files: string[] = [];
42
+
43
+ for (const entry of entries) {
44
+ const entryPath = path.join(root, entry.name);
45
+ if (entry.isDirectory()) {
46
+ files.push(...collectSourceFiles(entryPath));
47
+ continue;
48
+ }
49
+
50
+ if (entry.isFile() && isSupportedFile(entry.name)) {
51
+ files.push(entryPath);
52
+ }
53
+ }
54
+
55
+ return files;
56
+ }
57
+
58
+ function isSupportedFile(fileName: string): boolean {
59
+ return (
60
+ (fileName.endsWith('.ts') || fileName.endsWith('.tsx')) &&
61
+ !fileName.endsWith('.d.ts') &&
62
+ !fileName.endsWith('.d.tsx')
63
+ );
64
+ }
65
+
66
+ function checkFileLimits(filePath: string): void {
67
+ const content = fs.readFileSync(filePath, 'utf8');
68
+ const lineCount = content.split(/\r?\n/).length;
69
+ const relativePath = path.relative(path.join(projectRoot, '..'), filePath);
70
+
71
+ if (lineCount > FILE_ERROR_LINES) {
72
+ violations.push({
73
+ level: 'error',
74
+ message: `${relativePath} has ${lineCount} lines (error > ${FILE_ERROR_LINES})`,
75
+ });
76
+ } else if (lineCount > FILE_WARN_LINES) {
77
+ violations.push({
78
+ level: 'warn',
79
+ message: `${relativePath} has ${lineCount} lines (warn > ${FILE_WARN_LINES})`,
80
+ });
81
+ }
82
+
83
+ const sourceFile = ts.createSourceFile(
84
+ filePath,
85
+ content,
86
+ ts.ScriptTarget.Latest,
87
+ true,
88
+ filePath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
89
+ );
90
+
91
+ visitFunctions(sourceFile, relativePath);
92
+ }
93
+
94
+ function visitFunctions(sourceFile: ts.SourceFile, relativePath: string): void {
95
+ const queue: ts.Node[] = [sourceFile];
96
+
97
+ while (queue.length > 0) {
98
+ const current = queue.shift();
99
+ if (!current) {
100
+ continue;
101
+ }
102
+
103
+ if (isFunctionWithBody(current)) {
104
+ recordFunctionLength(current, sourceFile, relativePath);
105
+ }
106
+
107
+ current.forEachChild((child) => {
108
+ queue.push(child);
109
+ });
110
+ }
111
+ }
112
+
113
+ function isFunctionWithBody(
114
+ node: ts.Node,
115
+ ): node is ts.FunctionLikeDeclarationBase & { body: ts.Block } {
116
+ return (
117
+ ts.isFunctionLike(node) &&
118
+ 'body' in node &&
119
+ node.body !== undefined &&
120
+ ts.isBlock(node.body as ts.Node)
121
+ );
122
+ }
123
+
124
+ function recordFunctionLength(
125
+ node: ts.FunctionLikeDeclarationBase & { body: ts.Block },
126
+ sourceFile: ts.SourceFile,
127
+ relativePath: string,
128
+ ): void {
129
+ const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
130
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
131
+ const functionLines = end.line - start.line + 1;
132
+ const functionName = getFunctionName(node);
133
+
134
+ if (functionLines > FUNCTION_ERROR_LINES) {
135
+ violations.push({
136
+ level: 'error',
137
+ message: `${relativePath} :: ${functionName} is ${functionLines} lines (error > ${FUNCTION_ERROR_LINES})`,
138
+ });
139
+ } else if (functionLines > FUNCTION_WARN_LINES) {
140
+ violations.push({
141
+ level: 'warn',
142
+ message: `${relativePath} :: ${functionName} is ${functionLines} lines (warn > ${FUNCTION_WARN_LINES})`,
143
+ });
144
+ }
145
+ }
146
+
147
+ function getFunctionName(node: ts.FunctionLikeDeclarationBase): string {
148
+ const name = ts.getNameOfDeclaration(node);
149
+ if (name && ts.isIdentifier(name)) {
150
+ return name.text;
151
+ }
152
+
153
+ return '<anonymous>';
154
+ }
155
+
156
+ const logger = getLogger('nui:check-limits');
157
+
158
+ function reportViolations(results: Violation[]): void {
159
+ const errors = results.filter((violation) => violation.level === 'error');
160
+
161
+ for (const violation of results) {
162
+ if (violation.level === 'error') {
163
+ logger.error(violation.message);
164
+ } else {
165
+ logger.warn(violation.message);
166
+ }
167
+ }
168
+
169
+ if (errors.length > 0) {
170
+ process.exitCode = 1;
171
+ return;
172
+ }
173
+
174
+ if (results.length === 0) {
175
+ logger.log('limit checks passed');
176
+ }
177
+ }
@@ -0,0 +1,71 @@
1
+ import { spawn } from 'child_process';
2
+ import { dirname, join } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const root = join(__dirname, '..');
7
+
8
+ const args = process.argv.slice(2);
9
+ const bunArgs = ['run', 'src/main.tsx', ...args];
10
+
11
+ const child = spawn('bun', bunArgs, {
12
+ cwd: root,
13
+ stdio: 'inherit',
14
+ env: {
15
+ ...process.env,
16
+ DEV: 'true',
17
+ },
18
+ });
19
+
20
+ let cleaned = false;
21
+ const cleanup = (code, signal) => {
22
+ if (cleaned) {
23
+ return;
24
+ }
25
+ cleaned = true;
26
+ // Ensure we leave the terminal in cooked mode even on abrupt exits.
27
+ try {
28
+ // Reset modes similar to tput cnorm; clear mouse/alt-screen.
29
+ process.stdout.write(
30
+ '\u001b[?1000l\u001b[?1002l\u001b[?1003l\u001b[?1006l\u001b[?25h\u001b[?1049l',
31
+ );
32
+ } catch {
33
+ // ignore
34
+ }
35
+
36
+ if (signal) {
37
+ const signalCode = 128 + (signal === 'SIGINT' ? 2 : 15);
38
+ process.exit(signalCode);
39
+ return;
40
+ }
41
+ process.exit(code ?? 0);
42
+ };
43
+
44
+ const forwardSignal = (signal) => {
45
+ if (!child.killed) {
46
+ child.kill(signal);
47
+ }
48
+ // If the child drags its feet, escalate to SIGKILL then exit.
49
+ const killTimer = setTimeout(() => {
50
+ if (!child.killed) {
51
+ child.kill('SIGKILL');
52
+ }
53
+ }, 800);
54
+ killTimer.unref();
55
+
56
+ const exitTimer = setTimeout(() => {
57
+ cleanup(undefined, signal);
58
+ }, 1200);
59
+ exitTimer.unref();
60
+ };
61
+
62
+ ['SIGINT', 'SIGTERM'].forEach((signal) => {
63
+ process.on(signal, () => forwardSignal(signal));
64
+ });
65
+
66
+ child.on('exit', (code, signal) => cleanup(code, signal));
67
+
68
+ child.on('error', (error) => {
69
+ console.error('Failed to start UI process:', error);
70
+ cleanup(1);
71
+ });