npcts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/dist/adapters/base.d.ts +13 -0
  4. package/dist/adapters/base.js +1 -0
  5. package/dist/adapters/electron/bridge.d.ts +4 -0
  6. package/dist/adapters/electron/bridge.js +88 -0
  7. package/dist/adapters/index.d.ts +2 -0
  8. package/dist/adapters/index.js +3 -0
  9. package/dist/core/browser.d.ts +25 -0
  10. package/dist/core/browser.js +1 -0
  11. package/dist/core/chat.d.ts +41 -0
  12. package/dist/core/chat.js +1 -0
  13. package/dist/core/database.d.ts +56 -0
  14. package/dist/core/database.js +50 -0
  15. package/dist/core/files.d.ts +24 -0
  16. package/dist/core/files.js +15 -0
  17. package/dist/core/index.d.ts +9 -0
  18. package/dist/core/index.js +10 -0
  19. package/dist/core/jobs.d.ts +20 -0
  20. package/dist/core/jobs.js +1 -0
  21. package/dist/core/layout.d.ts +30 -0
  22. package/dist/core/layout.js +41 -0
  23. package/dist/core/stream.d.ts +10 -0
  24. package/dist/core/stream.js +1 -0
  25. package/dist/core/types.d.ts +23 -0
  26. package/dist/core/types.js +1 -0
  27. package/dist/core/utils.d.ts +19 -0
  28. package/dist/core/utils.js +19 -0
  29. package/dist/index.d.ts +25 -0
  30. package/dist/index.js +29 -0
  31. package/dist/ui/chat/components/ChatHeaderBar.d.ts +13 -0
  32. package/dist/ui/chat/components/ChatHeaderBar.js +32 -0
  33. package/dist/ui/chat/components/ChatInterface.d.ts +10 -0
  34. package/dist/ui/chat/components/ChatInterface.js +19 -0
  35. package/dist/ui/chat/components/ChatMessage.d.ts +7 -0
  36. package/dist/ui/chat/components/ChatMessage.js +10 -0
  37. package/dist/ui/chat/components/ChatPane.d.ts +20 -0
  38. package/dist/ui/chat/components/ChatPane.js +20 -0
  39. package/dist/ui/chat/components/ChatView.d.ts +10 -0
  40. package/dist/ui/chat/components/ChatView.js +36 -0
  41. package/dist/ui/chat/components/ConversationList.d.ts +28 -0
  42. package/dist/ui/chat/components/ConversationList.js +113 -0
  43. package/dist/ui/chat/components/InPaneSearchBar.d.ts +12 -0
  44. package/dist/ui/chat/components/InPaneSearchBar.js +44 -0
  45. package/dist/ui/chat/components/InputArea.d.ts +7 -0
  46. package/dist/ui/chat/components/InputArea.js +46 -0
  47. package/dist/ui/chat/components/MessageAttachments.d.ts +5 -0
  48. package/dist/ui/chat/components/MessageAttachments.js +6 -0
  49. package/dist/ui/chat/components/MessageItem.d.ts +28 -0
  50. package/dist/ui/chat/components/MessageItem.js +43 -0
  51. package/dist/ui/chat/components/PredictiveTextOverlay.d.ts +10 -0
  52. package/dist/ui/chat/components/PredictiveTextOverlay.js +75 -0
  53. package/dist/ui/chat/context/ChatContext.d.ts +33 -0
  54. package/dist/ui/chat/context/ChatContext.js +157 -0
  55. package/dist/ui/chat/hooks/useAutoScroll.d.ts +1 -0
  56. package/dist/ui/chat/hooks/useAutoScroll.js +11 -0
  57. package/dist/ui/chat/index.d.ts +7 -0
  58. package/dist/ui/chat/index.js +7 -0
  59. package/dist/ui/dashboard/ChartWidget.d.ts +18 -0
  60. package/dist/ui/dashboard/ChartWidget.js +98 -0
  61. package/dist/ui/dashboard/QueryWidget.d.ts +29 -0
  62. package/dist/ui/dashboard/QueryWidget.js +117 -0
  63. package/dist/ui/dashboard/TableWidget.d.ts +14 -0
  64. package/dist/ui/dashboard/TableWidget.js +117 -0
  65. package/dist/ui/dashboard/Widget.d.ts +40 -0
  66. package/dist/ui/dashboard/Widget.js +26 -0
  67. package/dist/ui/dashboard/WidgetBuilder.d.ts +47 -0
  68. package/dist/ui/dashboard/WidgetBuilder.js +286 -0
  69. package/dist/ui/dashboard/WidgetGrid.d.ts +19 -0
  70. package/dist/ui/dashboard/WidgetGrid.js +11 -0
  71. package/dist/ui/dashboard/index.d.ts +8 -0
  72. package/dist/ui/dashboard/index.js +4 -0
  73. package/dist/ui/dialogs/BrowserUrlDialog.d.ts +8 -0
  74. package/dist/ui/dialogs/BrowserUrlDialog.js +203 -0
  75. package/dist/ui/dialogs/index.d.ts +1 -0
  76. package/dist/ui/dialogs/index.js +1 -0
  77. package/dist/ui/editors/ImageEditor.d.ts +49 -0
  78. package/dist/ui/editors/ImageEditor.js +264 -0
  79. package/dist/ui/editors/index.d.ts +2 -0
  80. package/dist/ui/editors/index.js +1 -0
  81. package/dist/ui/execution/ExecutionFilters.d.ts +11 -0
  82. package/dist/ui/execution/ExecutionFilters.js +27 -0
  83. package/dist/ui/execution/ExecutionHistoryList.d.ts +19 -0
  84. package/dist/ui/execution/ExecutionHistoryList.js +35 -0
  85. package/dist/ui/execution/index.d.ts +3 -0
  86. package/dist/ui/execution/index.js +2 -0
  87. package/dist/ui/files/components/FileTree.d.ts +18 -0
  88. package/dist/ui/files/components/FileTree.js +61 -0
  89. package/dist/ui/files/components/Sidebar.d.ts +18 -0
  90. package/dist/ui/files/components/Sidebar.js +67 -0
  91. package/dist/ui/files/components/index.d.ts +2 -0
  92. package/dist/ui/files/components/index.js +2 -0
  93. package/dist/ui/files/context/FileSystemContext.d.ts +23 -0
  94. package/dist/ui/files/context/FileSystemContext.js +65 -0
  95. package/dist/ui/files/context/index.d.ts +1 -0
  96. package/dist/ui/files/context/index.js +1 -0
  97. package/dist/ui/files/index.d.ts +2 -0
  98. package/dist/ui/files/index.js +2 -0
  99. package/dist/ui/hooks/index.d.ts +4 -0
  100. package/dist/ui/hooks/index.js +3 -0
  101. package/dist/ui/hooks/useDebounce.d.ts +8 -0
  102. package/dist/ui/hooks/useDebounce.js +18 -0
  103. package/dist/ui/hooks/usePaneTracking.d.ts +15 -0
  104. package/dist/ui/hooks/usePaneTracking.js +20 -0
  105. package/dist/ui/hooks/useQuery.d.ts +25 -0
  106. package/dist/ui/hooks/useQuery.js +71 -0
  107. package/dist/ui/index.d.ts +19 -0
  108. package/dist/ui/index.js +20 -0
  109. package/dist/ui/jinx/JinxEditor.d.ts +20 -0
  110. package/dist/ui/jinx/JinxEditor.js +34 -0
  111. package/dist/ui/jinx/JinxTree.d.ts +14 -0
  112. package/dist/ui/jinx/JinxTree.js +65 -0
  113. package/dist/ui/jinx/index.d.ts +3 -0
  114. package/dist/ui/jinx/index.js +2 -0
  115. package/dist/ui/knowledge-graph/KGControls.d.ts +12 -0
  116. package/dist/ui/knowledge-graph/KGControls.js +21 -0
  117. package/dist/ui/knowledge-graph/KGStats.d.ts +13 -0
  118. package/dist/ui/knowledge-graph/KGStats.js +18 -0
  119. package/dist/ui/knowledge-graph/KnowledgeGraphViewer.d.ts +22 -0
  120. package/dist/ui/knowledge-graph/KnowledgeGraphViewer.js +16 -0
  121. package/dist/ui/knowledge-graph/index.d.ts +4 -0
  122. package/dist/ui/knowledge-graph/index.js +3 -0
  123. package/dist/ui/layout/components/AppShell.d.ts +8 -0
  124. package/dist/ui/layout/components/AppShell.js +19 -0
  125. package/dist/ui/layout/components/ContentPaneContainer.d.ts +8 -0
  126. package/dist/ui/layout/components/ContentPaneContainer.js +95 -0
  127. package/dist/ui/layout/components/LayoutNode.d.ts +8 -0
  128. package/dist/ui/layout/components/LayoutNode.js +12 -0
  129. package/dist/ui/layout/components/PaneHeader.d.ts +17 -0
  130. package/dist/ui/layout/components/PaneHeader.js +40 -0
  131. package/dist/ui/layout/components/SplitView.d.ts +8 -0
  132. package/dist/ui/layout/components/SplitView.js +51 -0
  133. package/dist/ui/layout/components/Studio.d.ts +7 -0
  134. package/dist/ui/layout/components/Studio.js +12 -0
  135. package/dist/ui/layout/components/contextMenus/BrowserContextMenu.d.ts +13 -0
  136. package/dist/ui/layout/components/contextMenus/BrowserContextMenu.js +23 -0
  137. package/dist/ui/layout/components/contextMenus/EditorContextMenu.d.ts +15 -0
  138. package/dist/ui/layout/components/contextMenus/EditorContextMenu.js +32 -0
  139. package/dist/ui/layout/components/contextMenus/FileContextMenu.d.ts +15 -0
  140. package/dist/ui/layout/components/contextMenus/FileContextMenu.js +33 -0
  141. package/dist/ui/layout/components/contextMenus/PdfContextMenu.d.ts +13 -0
  142. package/dist/ui/layout/components/contextMenus/PdfContextMenu.js +23 -0
  143. package/dist/ui/layout/components/contextMenus/index.d.ts +4 -0
  144. package/dist/ui/layout/components/contextMenus/index.js +4 -0
  145. package/dist/ui/layout/components/index.d.ts +8 -0
  146. package/dist/ui/layout/components/index.js +8 -0
  147. package/dist/ui/layout/components/modals/AIEditModal.d.ts +9 -0
  148. package/dist/ui/layout/components/modals/AIEditModal.js +33 -0
  149. package/dist/ui/layout/components/modals/MemoryApprovalModal.d.ts +15 -0
  150. package/dist/ui/layout/components/modals/MemoryApprovalModal.js +23 -0
  151. package/dist/ui/layout/components/modals/PromptModal.d.ts +11 -0
  152. package/dist/ui/layout/components/modals/PromptModal.js +20 -0
  153. package/dist/ui/layout/components/modals/ResendModal.d.ts +16 -0
  154. package/dist/ui/layout/components/modals/ResendModal.js +22 -0
  155. package/dist/ui/layout/components/modals/index.d.ts +4 -0
  156. package/dist/ui/layout/components/modals/index.js +4 -0
  157. package/dist/ui/layout/context/LayoutContext.d.ts +32 -0
  158. package/dist/ui/layout/context/LayoutContext.js +144 -0
  159. package/dist/ui/layout/index.d.ts +2 -0
  160. package/dist/ui/layout/index.js +2 -0
  161. package/dist/ui/markdown/Markdown.d.ts +4 -0
  162. package/dist/ui/markdown/Markdown.js +4 -0
  163. package/dist/ui/memory/MemoryFilters.d.ts +12 -0
  164. package/dist/ui/memory/MemoryFilters.js +23 -0
  165. package/dist/ui/memory/MemoryList.d.ts +19 -0
  166. package/dist/ui/memory/MemoryList.js +36 -0
  167. package/dist/ui/memory/index.d.ts +3 -0
  168. package/dist/ui/memory/index.js +2 -0
  169. package/dist/ui/models/ModelCard.d.ts +16 -0
  170. package/dist/ui/models/ModelCard.js +30 -0
  171. package/dist/ui/models/ModelSelector.d.ts +13 -0
  172. package/dist/ui/models/ModelSelector.js +6 -0
  173. package/dist/ui/models/index.d.ts +3 -0
  174. package/dist/ui/models/index.js +2 -0
  175. package/dist/ui/npc/McpServerMenu.d.ts +15 -0
  176. package/dist/ui/npc/McpServerMenu.js +48 -0
  177. package/dist/ui/npc/NPCEditor.d.ts +21 -0
  178. package/dist/ui/npc/NPCEditor.js +17 -0
  179. package/dist/ui/npc/NPCList.d.ts +19 -0
  180. package/dist/ui/npc/NPCList.js +28 -0
  181. package/dist/ui/npc/index.d.ts +3 -0
  182. package/dist/ui/npc/index.js +2 -0
  183. package/dist/ui/photo/GalleryGrid.d.ts +25 -0
  184. package/dist/ui/photo/GalleryGrid.js +46 -0
  185. package/dist/ui/photo/ImageAdjustmentSliders.d.ts +37 -0
  186. package/dist/ui/photo/ImageAdjustmentSliders.js +56 -0
  187. package/dist/ui/photo/ImageLabelingCanvas.d.ts +47 -0
  188. package/dist/ui/photo/ImageLabelingCanvas.js +174 -0
  189. package/dist/ui/photo/ImageSourceTabs.d.ts +28 -0
  190. package/dist/ui/photo/ImageSourceTabs.js +46 -0
  191. package/dist/ui/photo/LayerPanel.d.ts +87 -0
  192. package/dist/ui/photo/LayerPanel.js +70 -0
  193. package/dist/ui/photo/Lightbox.d.ts +12 -0
  194. package/dist/ui/photo/Lightbox.js +90 -0
  195. package/dist/ui/photo/index.d.ts +6 -0
  196. package/dist/ui/photo/index.js +7 -0
  197. package/dist/ui/primitives/AutosizeTextarea.d.ts +8 -0
  198. package/dist/ui/primitives/AutosizeTextarea.js +17 -0
  199. package/dist/ui/primitives/Button.d.ts +7 -0
  200. package/dist/ui/primitives/Button.js +17 -0
  201. package/dist/ui/primitives/Card.d.ts +12 -0
  202. package/dist/ui/primitives/Card.js +8 -0
  203. package/dist/ui/primitives/Chart.d.ts +34 -0
  204. package/dist/ui/primitives/Chart.js +140 -0
  205. package/dist/ui/primitives/ContextMenu.d.ts +17 -0
  206. package/dist/ui/primitives/ContextMenu.js +33 -0
  207. package/dist/ui/primitives/DataTable.d.ts +13 -0
  208. package/dist/ui/primitives/DataTable.js +13 -0
  209. package/dist/ui/primitives/FileUpload.d.ts +10 -0
  210. package/dist/ui/primitives/FileUpload.js +24 -0
  211. package/dist/ui/primitives/ImageGrid.d.ts +21 -0
  212. package/dist/ui/primitives/ImageGrid.js +29 -0
  213. package/dist/ui/primitives/Input.d.ts +7 -0
  214. package/dist/ui/primitives/Input.js +10 -0
  215. package/dist/ui/primitives/Lightbox.d.ts +12 -0
  216. package/dist/ui/primitives/Lightbox.js +36 -0
  217. package/dist/ui/primitives/Modal.d.ts +10 -0
  218. package/dist/ui/primitives/Modal.js +33 -0
  219. package/dist/ui/primitives/RangeSlider.d.ts +13 -0
  220. package/dist/ui/primitives/RangeSlider.js +6 -0
  221. package/dist/ui/primitives/Select.d.ts +11 -0
  222. package/dist/ui/primitives/Select.js +10 -0
  223. package/dist/ui/primitives/Slider.d.ts +13 -0
  224. package/dist/ui/primitives/Slider.js +8 -0
  225. package/dist/ui/primitives/SortableList.d.ts +9 -0
  226. package/dist/ui/primitives/SortableList.js +19 -0
  227. package/dist/ui/primitives/Spinner.d.ts +2 -0
  228. package/dist/ui/primitives/Spinner.js +2 -0
  229. package/dist/ui/primitives/StarRating.d.ts +10 -0
  230. package/dist/ui/primitives/StarRating.js +10 -0
  231. package/dist/ui/primitives/Tabs.d.ts +15 -0
  232. package/dist/ui/primitives/Tabs.js +11 -0
  233. package/dist/ui/primitives/TagInput.d.ts +10 -0
  234. package/dist/ui/primitives/TagInput.js +25 -0
  235. package/dist/ui/primitives/index.d.ts +20 -0
  236. package/dist/ui/primitives/index.js +19 -0
  237. package/dist/ui/specialized/DiskUsageAnalyzer.d.ts +12 -0
  238. package/dist/ui/specialized/DiskUsageAnalyzer.js +38 -0
  239. package/dist/ui/specialized/OllamaModelManager.d.ts +2 -0
  240. package/dist/ui/specialized/OllamaModelManager.js +48 -0
  241. package/dist/ui/specialized/RichTextEditor.d.ts +8 -0
  242. package/dist/ui/specialized/RichTextEditor.js +64 -0
  243. package/dist/ui/specialized/SlideCanvas.d.ts +24 -0
  244. package/dist/ui/specialized/SlideCanvas.js +31 -0
  245. package/dist/ui/specialized/SpreadsheetGrid.d.ts +18 -0
  246. package/dist/ui/specialized/SpreadsheetGrid.js +28 -0
  247. package/dist/ui/specialized/StepEditor.d.ts +12 -0
  248. package/dist/ui/specialized/StepEditor.js +22 -0
  249. package/dist/ui/specialized/TerminalEmbed.d.ts +13 -0
  250. package/dist/ui/specialized/TerminalEmbed.js +50 -0
  251. package/dist/ui/specialized/index.d.ts +7 -0
  252. package/dist/ui/specialized/index.js +7 -0
  253. package/dist/ui/sql/SQLQueryEditor.d.ts +9 -0
  254. package/dist/ui/sql/SQLQueryEditor.js +10 -0
  255. package/dist/ui/sql/SQLResultsTable.d.ts +6 -0
  256. package/dist/ui/sql/SQLResultsTable.js +12 -0
  257. package/dist/ui/sql/SQLSchemaViewer.d.ts +14 -0
  258. package/dist/ui/sql/SQLSchemaViewer.js +18 -0
  259. package/dist/ui/sql/index.d.ts +3 -0
  260. package/dist/ui/sql/index.js +3 -0
  261. package/dist/ui/utils/cn.d.ts +1 -0
  262. package/dist/ui/utils/cn.js +1 -0
  263. package/dist/ui/utils/fileIcons.d.ts +2 -0
  264. package/dist/ui/utils/fileIcons.js +24 -0
  265. package/dist/ui/utils/fileUtils.d.ts +4 -0
  266. package/dist/ui/utils/fileUtils.js +11 -0
  267. package/dist/ui/utils/index.d.ts +3 -0
  268. package/dist/ui/utils/index.js +3 -0
  269. package/dist/ui/viewers/components/BrowserViewer.d.ts +9 -0
  270. package/dist/ui/viewers/components/BrowserViewer.js +44 -0
  271. package/dist/ui/viewers/components/CodeEditor.d.ts +11 -0
  272. package/dist/ui/viewers/components/CodeEditor.js +115 -0
  273. package/dist/ui/viewers/components/CsvViewer.d.ts +7 -0
  274. package/dist/ui/viewers/components/CsvViewer.js +18 -0
  275. package/dist/ui/viewers/components/ImageViewer.d.ts +7 -0
  276. package/dist/ui/viewers/components/ImageViewer.js +23 -0
  277. package/dist/ui/viewers/components/PdfViewer.d.ts +7 -0
  278. package/dist/ui/viewers/components/PdfViewer.js +29 -0
  279. package/dist/ui/viewers/components/Terminal.d.ts +7 -0
  280. package/dist/ui/viewers/components/Terminal.js +31 -0
  281. package/dist/ui/viewers/components/index.d.ts +6 -0
  282. package/dist/ui/viewers/components/index.js +6 -0
  283. package/dist/ui/viewers/index.d.ts +1 -0
  284. package/dist/ui/viewers/index.js +1 -0
  285. package/package.json +76 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 NPC Worldwide
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # npcts
2
+
3
+ TypeScript library for building NPC-powered applications with split-pane
4
+ layouts, file editors, terminals, chat interfaces, and file management.
5
+
6
+ ## Architecture
7
+
8
+ ### Core Interfaces
9
+ - `core/types.ts` - Base types (ModelInfo, Attachment, ToolCall)
10
+ - `core/chat.ts` - Chat client interface
11
+ - `core/files.ts` - File system client interface
12
+ - `core/browser.ts` - Browser client interface
13
+ - `core/jobs.ts` - Jobs/cron client interface
14
+ - `core/layout.ts` - Layout node types
15
+
16
+ ### Adapters
17
+ Platform-specific implementations of core interfaces:
18
+ - `adapters/base.ts` - AppServices interface definition
19
+ - `adapters/electron/bridge.ts` - Electron/window.api implementation
20
+
21
+ ### UI Components
22
+
23
+ #### Layout System
24
+ - `LayoutProvider` - Context for split pane state management
25
+ - `LayoutNodeComponent` - Recursive layout tree renderer
26
+ - `SplitView` - Resizable horizontal/vertical splits
27
+ - `PaneHeader` - Pane title bar with close/rename
28
+ - `ContentPaneContainer` - Content type router
29
+ - `AppShell` - Complete application with sidebar + layout
30
+
31
+ #### File Management
32
+ - `FileSystemProvider` - File operations context
33
+ - `FileTree` - Recursive directory tree
34
+ - `Sidebar` - Workspace sidebar with search
35
+
36
+ #### Content Viewers
37
+ - `CodeEditor` - CodeMirror-based editor with syntax highlighting
38
+ - `Terminal` - Basic terminal emulator
39
+ - `BrowserViewer` - Embedded browser frame
40
+ - `PdfViewer` - PDF document viewer
41
+ - `CsvViewer` - Spreadsheet table view
42
+ - `ImageViewer` - Image display with zoom/rotate
43
+
44
+ #### Chat
45
+ - `ChatProvider` - Chat state management with streaming
46
+ - `ChatInterface` - Complete chat UI
47
+ - `ChatView` - Message list with auto-scroll
48
+ - `InputArea` - Message input with file attachments
49
+ - `ConversationList` - Conversation sidebar
50
+
51
+ #### Primitives
52
+ - `AutosizeTextarea` - Auto-growing textarea
53
+ - `Spinner` - Loading indicator
54
+
55
+ ## Quick Start
56
+
57
+ ### With Electron
58
+ ```typescript
59
+ import { createElectronAdapter, AppShell } from "npcts";
60
+
61
+ const services = createElectronAdapter(window.api);
62
+
63
+ function App() {
64
+ return (
65
+ <AppShell
66
+ services={services}
67
+ workspacePath="/path/to/workspace"
68
+ />
69
+ );
70
+ }
71
+ ```
72
+
73
+ ### Custom Adapter
74
+ ```typescript
75
+ import type { AppServices, ChatClient, FileSystemClient } from "npcts";
76
+
77
+ const customServices: AppServices = {
78
+ chat: customChatClient,
79
+ files: customFileClient,
80
+ browser: customBrowserClient,
81
+ jobs: customJobsClient,
82
+ };
83
+ ```
84
+
85
+ ### Layout Only
86
+ ```typescript
87
+ import { LayoutProvider, Studio } from "npcts";
88
+
89
+ function App() {
90
+ return <Studio services={services} />;
91
+ }
92
+ ```
93
+
94
+ ## Project Structure
95
+ ```
96
+ src/
97
+ ├── adapters/ # Platform implementations
98
+ │ ├── base.ts
99
+ │ └── electron/
100
+ ├── core/ # Core interface definitions
101
+ │ ├── types.ts
102
+ │ ├── chat.ts
103
+ │ ├── files.ts
104
+ │ ├── browser.ts
105
+ │ ├── jobs.ts
106
+ │ └── layout.ts
107
+ └── ui/ # React components
108
+ ├── chat/ # Chat UI components
109
+ ├── layout/ # Split pane system
110
+ ├── viewers/ # Content viewers
111
+ ├── files/ # File management
112
+ ├── primitives/ # Base components
113
+ └── markdown/ # Markdown rendering
114
+ ```
115
+
116
+ ## Development
117
+ ```bash
118
+ npm install # Install dependencies
119
+ npm run build # Compile TypeScript
120
+ npm run dev # Watch mode
121
+ npm run check # Type check only
122
+ ```
123
+
124
+ ## Features
125
+
126
+ - 🎨 Split-pane layout system with drag-to-split
127
+ - 📁 File tree navigation with context menus
128
+ - 💬 Real-time chat with streaming support
129
+ - ✏️ Code editor with syntax highlighting
130
+ - 🖥️ Terminal emulator
131
+ - 🌐 Browser viewer
132
+ - 📄 PDF, CSV, and image viewers
133
+ - 🔌 Pluggable adapter system
134
+ - 📦 TypeScript-first with full type safety
135
+ - ⚛️ React 18+ compatible
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,13 @@
1
+ import type { BrowserClient } from "../core/browser";
2
+ import type { ChatClient } from "../core/chat";
3
+ import type { FileSystemClient } from "../core/files";
4
+ import type { JobClient } from "../core/jobs";
5
+ import type { DatabaseClient } from "../core/database";
6
+ export interface AppServices {
7
+ chat: ChatClient;
8
+ files: FileSystemClient;
9
+ jobs?: JobClient;
10
+ browser?: BrowserClient;
11
+ database?: DatabaseClient;
12
+ }
13
+ export type AdapterFactory<T = unknown> = (bridge: T) => AppServices;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { AdapterFactory } from "../base";
2
+ type ElectronApi = Record<string, any> | undefined;
3
+ export declare const createElectronAdapter: AdapterFactory<ElectronApi>;
4
+ export {};
@@ -0,0 +1,88 @@
1
+ const ensureApi = (api) => {
2
+ if (!api)
3
+ throw new Error("Electron preload api is not available on window.api");
4
+ return api;
5
+ };
6
+ const createChatClient = (rawApi) => {
7
+ const api = ensureApi(rawApi);
8
+ return {
9
+ listConversations: (workspacePath) => {
10
+ if (api.getConversationsInDirectory && workspacePath) {
11
+ return api.getConversationsInDirectory(workspacePath);
12
+ }
13
+ return api.getConversations?.(workspacePath ?? "") ?? Promise.resolve([]);
14
+ },
15
+ createConversation: (workspacePath) => api.createConversation?.({ directory_path: workspacePath }) ??
16
+ Promise.reject(new Error("createConversation not implemented")),
17
+ deleteConversation: (conversationId) => api.deleteConversation?.(conversationId) ?? Promise.resolve(),
18
+ listMessages: (conversationId) => api.getConversationMessages?.(conversationId) ?? Promise.resolve([]),
19
+ sendMessage: async (request) => {
20
+ const modelId = typeof request.model === "string" ? request.model : request.model.id;
21
+ if (request.stream && api.onStreamData) {
22
+ // The host should expose a stream API that yields chunks; we forward the generator when available.
23
+ const generator = api.executeCommandStream?.({
24
+ commandstr: request.prompt,
25
+ conversationId: request.conversationId,
26
+ model: modelId,
27
+ });
28
+ if (generator)
29
+ return generator;
30
+ }
31
+ const msg = await api.sendMessage?.({
32
+ conversationId: request.conversationId,
33
+ message: request.prompt,
34
+ model: modelId,
35
+ attachments: request.attachments,
36
+ });
37
+ return msg;
38
+ },
39
+ deleteMessage: (conversationId, messageId) => api.deleteMessage?.({ conversationId, messageId }) ?? Promise.resolve(),
40
+ };
41
+ };
42
+ const createFileSystemClient = (rawApi) => {
43
+ const api = ensureApi(rawApi);
44
+ return {
45
+ readDirectoryStructure: (dirPath) => api.readDirectoryStructure(dirPath),
46
+ readFileContent: (path) => api.readFileContent(path),
47
+ writeFileContent: (path, content) => api.writeFileContent(path, content),
48
+ createDirectory: (path) => api.createDirectory(path),
49
+ deleteFile: (path) => api.deleteFile(path),
50
+ deleteDirectory: (path) => api.deleteDirectory(path),
51
+ rename: (oldPath, newPath) => api.renameFile(oldPath, newPath),
52
+ };
53
+ };
54
+ const createJobClient = (rawApi) => {
55
+ const api = ensureApi(rawApi);
56
+ return {
57
+ listCronJobs: () => api.getCronDaemons(),
58
+ addCronJob: (job) => api.addCronJob(job),
59
+ removeCronJob: (id) => api.removeCronJob(id),
60
+ listDaemons: () => api.getCronDaemons(),
61
+ addDaemon: (daemon) => api.addDaemon(daemon),
62
+ removeDaemon: (id) => api.removeDaemon(id),
63
+ };
64
+ };
65
+ const createBrowserClient = (rawApi) => {
66
+ const api = ensureApi(rawApi);
67
+ return {
68
+ navigate: (url) => api.browserNavigate({ url }),
69
+ back: () => api.browserBack({}),
70
+ forward: () => api.browserForward({}),
71
+ refresh: () => api.browserRefresh({}),
72
+ getSelectedText: () => api.browserGetSelectedText({}),
73
+ listHistory: () => api.browserGetHistory({}),
74
+ addHistory: (entry) => api.browserAddToHistory(entry),
75
+ clearHistory: () => api.browserClearHistory({}),
76
+ listBookmarks: () => api.browserGetBookmarks({}),
77
+ addBookmark: (bookmark) => api.browserAddBookmark(bookmark),
78
+ deleteBookmark: (id) => api.browserDeleteBookmark({ id }),
79
+ };
80
+ };
81
+ export const createElectronAdapter = (bridge) => {
82
+ return {
83
+ chat: createChatClient(bridge),
84
+ files: createFileSystemClient(bridge),
85
+ jobs: createJobClient(bridge),
86
+ browser: createBrowserClient(bridge),
87
+ };
88
+ };
@@ -0,0 +1,2 @@
1
+ export * from './base';
2
+ export { createElectronAdapter } from './electron/bridge';
@@ -0,0 +1,3 @@
1
+ // Adapters module exports
2
+ export * from './base';
3
+ export { createElectronAdapter } from './electron/bridge';
@@ -0,0 +1,25 @@
1
+ export interface BrowserHistoryEntry {
2
+ id: string;
3
+ title?: string;
4
+ url: string;
5
+ visitedAt: string;
6
+ }
7
+ export interface Bookmark {
8
+ id: string;
9
+ title: string;
10
+ url: string;
11
+ folder?: string;
12
+ }
13
+ export interface BrowserClient {
14
+ navigate(url: string): Promise<void>;
15
+ back(): Promise<void>;
16
+ forward(): Promise<void>;
17
+ refresh(): Promise<void>;
18
+ getSelectedText(): Promise<string | null>;
19
+ listHistory(): Promise<BrowserHistoryEntry[]>;
20
+ addHistory(entry: Omit<BrowserHistoryEntry, "id" | "visitedAt">): Promise<BrowserHistoryEntry>;
21
+ clearHistory(): Promise<void>;
22
+ listBookmarks(): Promise<Bookmark[]>;
23
+ addBookmark(bookmark: Omit<Bookmark, "id">): Promise<Bookmark>;
24
+ deleteBookmark(id: string): Promise<void>;
25
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import type { Attachment, ModelInfo, ToolCall } from "./types";
2
+ export interface Conversation {
3
+ id: string;
4
+ title?: string;
5
+ workspacePath?: string;
6
+ createdAt?: string;
7
+ updatedAt?: string;
8
+ }
9
+ export interface ChatMessage {
10
+ id: string;
11
+ role: "user" | "assistant" | "system" | "tool";
12
+ content: string;
13
+ createdAt?: string;
14
+ attachments?: Attachment[];
15
+ toolCalls?: ToolCall[];
16
+ parentId?: string;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ export interface ChatStreamChunk {
20
+ id: string;
21
+ conversationId: string;
22
+ messageId: string;
23
+ delta: string;
24
+ done?: boolean;
25
+ }
26
+ export interface ChatSendRequest {
27
+ conversationId: string;
28
+ prompt: string;
29
+ model: ModelInfo | string;
30
+ attachments?: Attachment[];
31
+ context?: Record<string, unknown>;
32
+ stream?: boolean;
33
+ }
34
+ export interface ChatClient {
35
+ listConversations(workspacePath?: string): Promise<Conversation[]>;
36
+ createConversation(workspacePath?: string): Promise<Conversation>;
37
+ deleteConversation(conversationId: string): Promise<void>;
38
+ listMessages(conversationId: string): Promise<ChatMessage[]>;
39
+ sendMessage(request: ChatSendRequest): Promise<ChatMessage | AsyncGenerator<ChatStreamChunk>>;
40
+ deleteMessage(conversationId: string, messageId: string): Promise<void>;
41
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ export interface QueryResult<T = Record<string, unknown>> {
2
+ result?: T[];
3
+ data?: T[];
4
+ error?: string;
5
+ rowsAffected?: number;
6
+ }
7
+ export interface TableInfo {
8
+ name: string;
9
+ type: string;
10
+ }
11
+ export interface ColumnInfo {
12
+ name: string;
13
+ type: string;
14
+ nullable?: boolean;
15
+ primaryKey?: boolean;
16
+ defaultValue?: unknown;
17
+ }
18
+ export interface DatabaseClient {
19
+ /**
20
+ * Execute a SQL query and return results
21
+ */
22
+ executeSQL(query: string, params?: unknown[]): Promise<QueryResult>;
23
+ /**
24
+ * Get list of tables in the database
25
+ */
26
+ getTables(): Promise<string[]>;
27
+ /**
28
+ * Get schema information for a specific table
29
+ */
30
+ getTableSchema(tableName: string): Promise<ColumnInfo[]>;
31
+ /**
32
+ * Execute multiple queries in a transaction
33
+ */
34
+ transaction?(queries: string[]): Promise<QueryResult[]>;
35
+ }
36
+ export interface DatabaseConfig {
37
+ type: 'sqlite' | 'postgres' | 'mysql' | 'custom';
38
+ connectionString?: string;
39
+ database?: string;
40
+ host?: string;
41
+ port?: number;
42
+ user?: string;
43
+ password?: string;
44
+ }
45
+ export declare function normalizeQueryResult<T = Record<string, unknown>>(response: QueryResult<T> | T[] | {
46
+ rows?: T[];
47
+ data?: T[];
48
+ result?: T[];
49
+ }): T[];
50
+ export declare function createWindowApiDatabaseClient(api: {
51
+ executeSQL?: (params: {
52
+ query: string;
53
+ }) => Promise<QueryResult>;
54
+ getTables?: () => Promise<string[]>;
55
+ getTableSchema?: (table: string) => Promise<ColumnInfo[]>;
56
+ }): DatabaseClient;
@@ -0,0 +1,50 @@
1
+ // Database abstraction for configurable backends
2
+ // Helper to normalize query results from different backends
3
+ export function normalizeQueryResult(response) {
4
+ if (Array.isArray(response)) {
5
+ return response;
6
+ }
7
+ if ('rows' in response && Array.isArray(response.rows)) {
8
+ return response.rows;
9
+ }
10
+ if ('data' in response && Array.isArray(response.data)) {
11
+ return response.data;
12
+ }
13
+ if ('result' in response && Array.isArray(response.result)) {
14
+ return response.result;
15
+ }
16
+ return [];
17
+ }
18
+ // Create a database client from window.api (common pattern)
19
+ export function createWindowApiDatabaseClient(api) {
20
+ return {
21
+ async executeSQL(query, _params) {
22
+ if (!api.executeSQL) {
23
+ return { error: 'executeSQL not available' };
24
+ }
25
+ return api.executeSQL({ query });
26
+ },
27
+ async getTables() {
28
+ if (api.getTables) {
29
+ return api.getTables();
30
+ }
31
+ // Fallback: try to query sqlite_master
32
+ const result = await this.executeSQL("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'");
33
+ return normalizeQueryResult(result).map((r) => r.name || '');
34
+ },
35
+ async getTableSchema(tableName) {
36
+ if (api.getTableSchema) {
37
+ return api.getTableSchema(tableName);
38
+ }
39
+ // Fallback: PRAGMA for SQLite
40
+ const result = await this.executeSQL(`PRAGMA table_info(${tableName})`);
41
+ return normalizeQueryResult(result).map((r) => ({
42
+ name: r.name || '',
43
+ type: r.type || 'unknown',
44
+ nullable: !r.notnull,
45
+ primaryKey: !!r.pk,
46
+ defaultValue: r.dflt_value
47
+ }));
48
+ }
49
+ };
50
+ }
@@ -0,0 +1,24 @@
1
+ export interface FileNode {
2
+ path: string;
3
+ name: string;
4
+ isDirectory: boolean;
5
+ sizeBytes?: number;
6
+ modifiedAt?: string;
7
+ children?: FileNode[];
8
+ }
9
+ export interface FileSystemClient {
10
+ readDirectoryStructure(path: string): Promise<FileNode>;
11
+ readFileContent(path: string): Promise<string>;
12
+ writeFileContent(path: string, content: string): Promise<void>;
13
+ createDirectory(path: string): Promise<void>;
14
+ deleteFile(path: string): Promise<void>;
15
+ deleteDirectory(path: string): Promise<void>;
16
+ rename(oldPath: string, newPath: string): Promise<void>;
17
+ }
18
+ /**
19
+ * Normalize a file path by converting backslashes to forward slashes
20
+ * and removing trailing slashes
21
+ * @param path - The path to normalize (can be null/undefined)
22
+ * @returns Normalized path string, or empty string if input is null/undefined
23
+ */
24
+ export declare const normalizePath: (path: string | null | undefined) => string;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Normalize a file path by converting backslashes to forward slashes
3
+ * and removing trailing slashes
4
+ * @param path - The path to normalize (can be null/undefined)
5
+ * @returns Normalized path string, or empty string if input is null/undefined
6
+ */
7
+ export const normalizePath = (path) => {
8
+ if (!path)
9
+ return '';
10
+ let normalizedPath = path.replace(/\\/g, '/');
11
+ if (normalizedPath.endsWith('/') && normalizedPath.length > 1) {
12
+ normalizedPath = normalizedPath.slice(0, -1);
13
+ }
14
+ return normalizedPath;
15
+ };
@@ -0,0 +1,9 @@
1
+ export * from './types';
2
+ export * from './layout';
3
+ export * from './files';
4
+ export * from './utils';
5
+ export * from './chat';
6
+ export * from './stream';
7
+ export * from './browser';
8
+ export * from './jobs';
9
+ export * from './database';
@@ -0,0 +1,10 @@
1
+ // Core module exports
2
+ export * from './types';
3
+ export * from './layout';
4
+ export * from './files';
5
+ export * from './utils';
6
+ export * from './chat';
7
+ export * from './stream';
8
+ export * from './browser';
9
+ export * from './jobs';
10
+ export * from './database';
@@ -0,0 +1,20 @@
1
+ export interface CronJob {
2
+ id: string;
3
+ schedule: string;
4
+ command: string;
5
+ label?: string;
6
+ }
7
+ export interface Daemon {
8
+ id: string;
9
+ name: string;
10
+ command: string;
11
+ status: "running" | "stopped" | "unknown";
12
+ }
13
+ export interface JobClient {
14
+ listCronJobs(): Promise<CronJob[]>;
15
+ addCronJob(job: Omit<CronJob, "id">): Promise<CronJob>;
16
+ removeCronJob(id: string): Promise<void>;
17
+ listDaemons(): Promise<Daemon[]>;
18
+ addDaemon(daemon: Omit<Daemon, "id" | "status">): Promise<Daemon>;
19
+ removeDaemon(id: string): Promise<void>;
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ export type SplitDirection = 'horizontal' | 'vertical';
2
+ export interface SplitNode {
3
+ type: 'split';
4
+ id: string;
5
+ direction: SplitDirection;
6
+ children: LayoutNode[];
7
+ sizes: number[];
8
+ }
9
+ export interface ContentNode {
10
+ type: 'content';
11
+ id: string;
12
+ contentType: string;
13
+ data?: any;
14
+ }
15
+ export type LayoutNode = SplitNode | ContentNode;
16
+ /**
17
+ * Find a node in the layout tree by following a path of indices
18
+ * @param node - The root layout node to search from
19
+ * @param path - Array of child indices to follow
20
+ * @returns The node at the specified path, or null if not found
21
+ */
22
+ export declare const findNodeByPath: (node: LayoutNode | null, path: number[]) => LayoutNode | null;
23
+ /**
24
+ * Find the path to a node with the given ID in the layout tree
25
+ * @param node - The root layout node to search from
26
+ * @param id - The ID of the node to find
27
+ * @param currentPath - The current path (used internally for recursion)
28
+ * @returns Array of indices representing the path to the node, or null if not found
29
+ */
30
+ export declare const findNodePath: (node: LayoutNode | null, id: string, currentPath?: number[]) => number[] | null;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Find a node in the layout tree by following a path of indices
3
+ * @param node - The root layout node to search from
4
+ * @param path - Array of child indices to follow
5
+ * @returns The node at the specified path, or null if not found
6
+ */
7
+ export const findNodeByPath = (node, path) => {
8
+ if (!node || !path)
9
+ return null;
10
+ let currentNode = node;
11
+ for (const index of path) {
12
+ if (currentNode && currentNode.type === 'split' && currentNode.children && currentNode.children[index]) {
13
+ currentNode = currentNode.children[index];
14
+ }
15
+ else {
16
+ return null;
17
+ }
18
+ }
19
+ return currentNode;
20
+ };
21
+ /**
22
+ * Find the path to a node with the given ID in the layout tree
23
+ * @param node - The root layout node to search from
24
+ * @param id - The ID of the node to find
25
+ * @param currentPath - The current path (used internally for recursion)
26
+ * @returns Array of indices representing the path to the node, or null if not found
27
+ */
28
+ export const findNodePath = (node, id, currentPath = []) => {
29
+ if (!node)
30
+ return null;
31
+ if (node.id === id)
32
+ return currentPath;
33
+ if (node.type === 'split') {
34
+ for (let i = 0; i < node.children.length; i++) {
35
+ const result = findNodePath(node.children[i], id, [...currentPath, i]);
36
+ if (result)
37
+ return result;
38
+ }
39
+ }
40
+ return null;
41
+ };
@@ -0,0 +1,10 @@
1
+ export type StreamStatus = "idle" | "streaming" | "error";
2
+ export interface StreamController {
3
+ streamId: string;
4
+ abort(): Promise<void> | void;
5
+ }
6
+ export interface StreamHandlers<TChunk> {
7
+ onChunk: (chunk: TChunk) => void;
8
+ onComplete?: () => void;
9
+ onError?: (error: unknown) => void;
10
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ export type Provider = "openai" | "ollama" | "anthropic" | "local" | string;
2
+ export interface Attachment {
3
+ id: string;
4
+ name: string;
5
+ path: string;
6
+ mime?: string;
7
+ sizeBytes?: number;
8
+ }
9
+ export interface ModelInfo {
10
+ id: string;
11
+ provider: Provider;
12
+ displayName?: string;
13
+ contextWindow?: number;
14
+ supportsImages?: boolean;
15
+ supportsTools?: boolean;
16
+ }
17
+ export interface ToolCall {
18
+ id: string;
19
+ name: string;
20
+ arguments: Record<string, unknown>;
21
+ status?: "pending" | "running" | "succeeded" | "failed";
22
+ output?: string;
23
+ }
@@ -0,0 +1 @@
1
+ export {};