xtralab 0.14.1 → 0.15.1

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 (236) hide show
  1. package/README.md +10 -0
  2. package/lib/about/icons.d.ts +0 -5
  3. package/lib/about/icons.js +0 -5
  4. package/lib/about/index.d.ts +4 -8
  5. package/lib/about/index.js +6 -17
  6. package/lib/agentSessions.d.ts +9 -29
  7. package/lib/agentSessions.js +2 -7
  8. package/lib/askAgent/editorSelection.d.ts +20 -26
  9. package/lib/askAgent/editorSelection.js +11 -26
  10. package/lib/askAgent/icons.d.ts +2 -3
  11. package/lib/askAgent/icons.js +2 -3
  12. package/lib/askAgent/index.d.ts +4 -26
  13. package/lib/askAgent/index.js +54 -158
  14. package/lib/askAgent/popup.d.ts +12 -16
  15. package/lib/askAgent/popup.js +18 -37
  16. package/lib/askAgent/prompt.d.ts +3 -5
  17. package/lib/askAgent/prompt.js +6 -19
  18. package/lib/askAgent/queue.d.ts +11 -21
  19. package/lib/askAgent/queue.js +9 -19
  20. package/lib/askAgent/queuePanel.d.ts +13 -18
  21. package/lib/askAgent/queuePanel.js +15 -37
  22. package/lib/askAgent/targetPicker.d.ts +2 -9
  23. package/lib/askAgent/targetPicker.js +6 -11
  24. package/lib/askAgent/tokens.d.ts +32 -46
  25. package/lib/askAgent/tokens.js +4 -6
  26. package/lib/commandBar/index.d.ts +4 -13
  27. package/lib/commandBar/index.js +21 -39
  28. package/lib/customPanel/index.d.ts +7 -0
  29. package/lib/customPanel/index.js +89 -0
  30. package/lib/editorBreadcrumbs/index.d.ts +3 -6
  31. package/lib/editorBreadcrumbs/index.js +10 -6
  32. package/lib/editorBreadcrumbs/widget.d.ts +17 -4
  33. package/lib/editorBreadcrumbs/widget.js +11 -17
  34. package/lib/editorIndent/index.d.ts +4 -12
  35. package/lib/editorIndent/index.js +8 -23
  36. package/lib/fileBrowser/commands.d.ts +28 -19
  37. package/lib/fileBrowser/commands.js +51 -98
  38. package/lib/fileBrowser/contents.d.ts +14 -0
  39. package/lib/fileBrowser/contents.js +28 -0
  40. package/lib/fileBrowser/dragAndDrop.d.ts +79 -0
  41. package/lib/fileBrowser/dragAndDrop.js +110 -0
  42. package/lib/fileBrowser/fileBrowser.d.ts +21 -9
  43. package/lib/fileBrowser/fileBrowser.js +211 -405
  44. package/lib/fileBrowser/gitStatus.d.ts +4 -9
  45. package/lib/fileBrowser/gitStatus.js +7 -17
  46. package/lib/fileBrowser/gitignore.d.ts +4 -17
  47. package/lib/fileBrowser/gitignore.js +4 -25
  48. package/lib/fileBrowser/icons.d.ts +7 -17
  49. package/lib/fileBrowser/icons.js +25 -80
  50. package/lib/fileBrowser/index.js +41 -10
  51. package/lib/fileBrowser/widget.d.ts +170 -53
  52. package/lib/fileBrowser/widget.js +242 -18
  53. package/lib/fileTypeIcons/index.js +0 -10
  54. package/lib/git/api.d.ts +5 -13
  55. package/lib/git/api.js +10 -36
  56. package/lib/git/askRequest.d.ts +4 -8
  57. package/lib/git/askRequest.js +6 -20
  58. package/lib/git/commands.d.ts +40 -5
  59. package/lib/git/commands.js +16 -10
  60. package/lib/git/diffModel.js +4 -0
  61. package/lib/git/diffSurface.d.ts +41 -55
  62. package/lib/git/diffSurface.js +42 -117
  63. package/lib/git/diffWidget.d.ts +81 -2
  64. package/lib/git/diffWidget.js +62 -12
  65. package/lib/git/imageDiff.d.ts +5 -6
  66. package/lib/git/imageDiff.js +18 -48
  67. package/lib/git/index.d.ts +0 -3
  68. package/lib/git/index.js +3 -8
  69. package/lib/git/notebookDiff.d.ts +110 -33
  70. package/lib/git/notebookDiff.js +52 -195
  71. package/lib/git/tokens.d.ts +73 -31
  72. package/lib/git/tokens.js +2 -3
  73. package/lib/highlight/index.d.ts +4 -10
  74. package/lib/highlight/index.js +10 -41
  75. package/lib/index.d.ts +0 -9
  76. package/lib/index.js +2 -9
  77. package/lib/launcher/agents.d.ts +55 -51
  78. package/lib/launcher/agents.js +25 -54
  79. package/lib/launcher/availability.d.ts +3 -9
  80. package/lib/launcher/availability.js +3 -9
  81. package/lib/launcher/commands.d.ts +7 -32
  82. package/lib/launcher/commands.js +14 -45
  83. package/lib/launcher/dashboard.d.ts +19 -24
  84. package/lib/launcher/dashboard.js +21 -67
  85. package/lib/launcher/editorRegistry.d.ts +10 -22
  86. package/lib/launcher/editorRegistry.js +14 -18
  87. package/lib/launcher/editors.d.ts +39 -45
  88. package/lib/launcher/editors.js +8 -34
  89. package/lib/launcher/icons.d.ts +0 -12
  90. package/lib/launcher/icons.js +14 -37
  91. package/lib/launcher/index.js +12 -55
  92. package/lib/launcher/invocation.d.ts +4 -10
  93. package/lib/launcher/invocation.js +7 -22
  94. package/lib/launcher/registry.d.ts +9 -7
  95. package/lib/launcher/registry.js +9 -7
  96. package/lib/launcher/schemaDefaults.d.ts +2 -9
  97. package/lib/launcher/schemaDefaults.js +37 -13
  98. package/lib/launcher/tokens.d.ts +10 -22
  99. package/lib/launcher/tokens.js +5 -8
  100. package/lib/menuBar/index.d.ts +3 -10
  101. package/lib/menuBar/index.js +11 -28
  102. package/lib/menus/index.d.ts +3 -9
  103. package/lib/menus/index.js +14 -30
  104. package/lib/omnibox/files.d.ts +2 -4
  105. package/lib/omnibox/files.js +5 -11
  106. package/lib/omnibox/index.d.ts +4 -14
  107. package/lib/omnibox/index.js +9 -27
  108. package/lib/omnibox/model.d.ts +38 -10
  109. package/lib/omnibox/model.js +15 -33
  110. package/lib/omnibox/recents.d.ts +15 -17
  111. package/lib/omnibox/recents.js +12 -17
  112. package/lib/omnibox/tokens.d.ts +5 -10
  113. package/lib/omnibox/tokens.js +2 -6
  114. package/lib/omnibox/widget.d.ts +11 -7
  115. package/lib/omnibox/widget.js +8 -16
  116. package/lib/searchReplace/index.d.ts +4 -20
  117. package/lib/searchReplace/index.js +7 -27
  118. package/lib/showOutput/index.d.ts +3 -12
  119. package/lib/showOutput/index.js +6 -22
  120. package/lib/sidebar/index.d.ts +4 -13
  121. package/lib/sidebar/index.js +73 -46
  122. package/lib/terminalNotifications/index.d.ts +4 -10
  123. package/lib/terminalNotifications/index.js +6 -20
  124. package/lib/terminals/agentTerminals.d.ts +12 -5
  125. package/lib/terminals/agentTerminals.js +25 -44
  126. package/lib/terminals/detection.d.ts +4 -8
  127. package/lib/terminals/detection.js +4 -8
  128. package/lib/terminals/index.d.ts +0 -33
  129. package/lib/terminals/index.js +24 -102
  130. package/lib/terminals/model.d.ts +64 -139
  131. package/lib/terminals/model.js +80 -220
  132. package/lib/terminals/tokens.d.ts +11 -22
  133. package/lib/terminals/tokens.js +2 -2
  134. package/lib/terminals/widget.d.ts +72 -38
  135. package/lib/terminals/widget.js +173 -73
  136. package/lib/topBar/icons.d.ts +3 -8
  137. package/lib/topBar/icons.js +3 -8
  138. package/lib/topBar/index.d.ts +4 -11
  139. package/lib/topBar/index.js +10 -38
  140. package/lib/walkthrough/index.d.ts +4 -9
  141. package/lib/walkthrough/index.js +6 -20
  142. package/lib/walkthrough/panel.d.ts +40 -9
  143. package/lib/walkthrough/panel.js +4 -10
  144. package/package.json +2 -2
  145. package/schema/launcher.json +2 -2
  146. package/schema/sidebar.json +47 -7
  147. package/src/about/icons.ts +0 -5
  148. package/src/about/index.tsx +6 -17
  149. package/src/agentSessions.ts +9 -29
  150. package/src/askAgent/editorSelection.ts +22 -29
  151. package/src/askAgent/icons.ts +2 -3
  152. package/src/askAgent/index.ts +54 -158
  153. package/src/askAgent/popup.tsx +23 -45
  154. package/src/askAgent/prompt.ts +6 -19
  155. package/src/askAgent/queue.ts +13 -24
  156. package/src/askAgent/queuePanel.tsx +21 -46
  157. package/src/askAgent/targetPicker.tsx +5 -15
  158. package/src/askAgent/tokens.ts +32 -46
  159. package/src/commandBar/index.ts +24 -39
  160. package/src/customPanel/index.ts +119 -0
  161. package/src/editorBreadcrumbs/index.ts +10 -6
  162. package/src/editorBreadcrumbs/widget.ts +23 -17
  163. package/src/editorIndent/index.ts +17 -23
  164. package/src/fileBrowser/commands.ts +70 -98
  165. package/src/fileBrowser/contents.ts +33 -0
  166. package/src/fileBrowser/dragAndDrop.ts +188 -0
  167. package/src/fileBrowser/fileBrowser.tsx +259 -440
  168. package/src/fileBrowser/gitStatus.ts +7 -17
  169. package/src/fileBrowser/gitignore.ts +4 -25
  170. package/src/fileBrowser/icons.ts +25 -80
  171. package/src/fileBrowser/index.ts +43 -10
  172. package/src/fileBrowser/widget.tsx +344 -64
  173. package/src/fileTypeIcons/index.ts +0 -10
  174. package/src/git/api.ts +10 -36
  175. package/src/git/askRequest.ts +6 -20
  176. package/src/git/commands.ts +70 -10
  177. package/src/git/diffModel.ts +25 -0
  178. package/src/git/diffSurface.tsx +71 -159
  179. package/src/git/diffWidget.tsx +104 -14
  180. package/src/git/imageDiff.tsx +45 -51
  181. package/src/git/index.ts +3 -8
  182. package/src/git/notebookDiff.tsx +211 -238
  183. package/src/git/tokens.ts +73 -31
  184. package/src/highlight/index.ts +10 -41
  185. package/src/index.ts +2 -9
  186. package/src/launcher/agents.ts +74 -92
  187. package/src/launcher/availability.ts +3 -9
  188. package/src/launcher/commands.ts +14 -51
  189. package/src/launcher/dashboard.tsx +49 -88
  190. package/src/launcher/editorRegistry.ts +21 -29
  191. package/src/launcher/editors.ts +39 -58
  192. package/src/launcher/icons.ts +15 -37
  193. package/src/launcher/index.ts +12 -55
  194. package/src/launcher/invocation.ts +7 -22
  195. package/src/launcher/registry.ts +9 -7
  196. package/src/launcher/schemaDefaults.ts +43 -13
  197. package/src/launcher/tokens.ts +10 -22
  198. package/src/menuBar/index.ts +11 -28
  199. package/src/menus/index.ts +14 -30
  200. package/src/omnibox/files.ts +10 -14
  201. package/src/omnibox/index.ts +9 -27
  202. package/src/omnibox/model.ts +50 -38
  203. package/src/omnibox/recents.ts +17 -22
  204. package/src/omnibox/tokens.ts +5 -10
  205. package/src/omnibox/widget.tsx +14 -19
  206. package/src/searchReplace/index.ts +7 -27
  207. package/src/showOutput/index.ts +6 -22
  208. package/src/sidebar/index.ts +103 -52
  209. package/src/terminalNotifications/index.ts +42 -25
  210. package/src/terminals/agentTerminals.ts +25 -49
  211. package/src/terminals/detection.ts +4 -8
  212. package/src/terminals/index.ts +31 -102
  213. package/src/terminals/model.ts +130 -246
  214. package/src/terminals/tokens.ts +11 -22
  215. package/src/terminals/widget.tsx +229 -113
  216. package/src/topBar/icons.ts +3 -8
  217. package/src/topBar/index.ts +21 -44
  218. package/src/walkthrough/index.ts +6 -20
  219. package/src/walkthrough/panel.ts +40 -10
  220. package/style/about.css +2 -7
  221. package/style/askAgent.css +8 -40
  222. package/style/base.css +25 -73
  223. package/style/chrome.css +108 -308
  224. package/style/commandBar.css +4 -20
  225. package/style/customPanel.css +6 -0
  226. package/style/git.css +22 -184
  227. package/style/highlight.css +1 -3
  228. package/style/index.js +1 -0
  229. package/style/launcher.css +6 -70
  230. package/style/omnibox.css +2 -14
  231. package/style/showOutput.css +0 -6
  232. package/style/sidebar.css +29 -9
  233. package/style/tabs.css +5 -13
  234. package/style/terminals.css +18 -123
  235. package/style/topBar.css +2 -22
  236. package/style/walkthrough.css +0 -8
@@ -17,6 +17,36 @@ export function toCanonicalPath(child: Contents.IModel): string {
17
17
  return child.type === 'directory' ? `${child.path}${DIR_SUFFIX}` : child.path;
18
18
  }
19
19
 
20
+ /**
21
+ * Compute the canonical parent path for a canonical path. Returns
22
+ * {@link ROOT_LOAD_KEY} for top-level entries.
23
+ */
24
+ export function parentOf(canonicalPath: string): string {
25
+ const trimmed = canonicalPath.endsWith(DIR_SUFFIX)
26
+ ? canonicalPath.slice(0, -DIR_SUFFIX.length)
27
+ : canonicalPath;
28
+ const idx = trimmed.lastIndexOf(DIR_SUFFIX);
29
+ if (idx < 0) {
30
+ return ROOT_LOAD_KEY;
31
+ }
32
+ return `${trimmed.slice(0, idx)}${DIR_SUFFIX}`;
33
+ }
34
+
35
+ /**
36
+ * The last segment of a canonical path. Directories keep their trailing
37
+ * slash, so appending the result to a canonical directory path yields a
38
+ * canonical path again.
39
+ */
40
+ export function canonicalBasename(canonicalPath: string): string {
41
+ const isDir = canonicalPath.endsWith(DIR_SUFFIX);
42
+ const trimmed = isDir
43
+ ? canonicalPath.slice(0, -DIR_SUFFIX.length)
44
+ : canonicalPath;
45
+ const idx = trimmed.lastIndexOf(DIR_SUFFIX);
46
+ const base = idx < 0 ? trimmed : trimmed.slice(idx + DIR_SUFFIX.length);
47
+ return isDir ? `${base}${DIR_SUFFIX}` : base;
48
+ }
49
+
20
50
  /**
21
51
  * Strip the trailing slash that `@pierre/trees` uses for canonical directory
22
52
  * paths so the value can be sent to the Jupyter contents API.
@@ -30,6 +60,9 @@ export function toServerPath(canonicalPath: string): string {
30
60
  : canonicalPath;
31
61
  }
32
62
 
63
+ /**
64
+ * The immediate children of a directory, as canonical `@pierre/trees` paths.
65
+ */
33
66
  interface IListedDirectory {
34
67
  /**
35
68
  * Canonical paths for every immediate child of the requested directory.
@@ -0,0 +1,188 @@
1
+ import * as React from 'react';
2
+
3
+ import type {
4
+ FileTree,
5
+ FileTreeDragAndDropConfig,
6
+ FileTreeDropContext,
7
+ FileTreeDropResult,
8
+ FileTreeDropTarget
9
+ } from '@pierre/trees';
10
+
11
+ import { ROOT_LOAD_KEY, canonicalBasename, parentOf } from './contents';
12
+
13
+ /**
14
+ * One tree-model move a drop performs, as canonical paths.
15
+ */
16
+ export interface IDropMove {
17
+ /**
18
+ * The canonical path of the dragged item.
19
+ */
20
+ from: string;
21
+ /**
22
+ * The canonical destination path: its basename under the target directory.
23
+ */
24
+ to: string;
25
+ }
26
+
27
+ /**
28
+ * Receives drop outcomes from the `@pierre/trees` drag-and-drop
29
+ * machinery. Implemented inside the file browser's contents-sync
30
+ * effect, which owns the load-state and contents-API bookkeeping.
31
+ */
32
+ export interface ITreeDropHandler {
33
+ /**
34
+ * The tree applied the drop to its model: persist the move and
35
+ * re-key the load-state mirrors.
36
+ */
37
+ completeDrop(result: FileTreeDropResult): void;
38
+
39
+ /**
40
+ * The tree refused the drop (typically a name collision) and left
41
+ * its model untouched.
42
+ */
43
+ failedDrop(error: string, context: FileTreeDropContext): void;
44
+
45
+ /**
46
+ * A drop on the empty space below the last row: move the dragged
47
+ * paths to the workspace root.
48
+ */
49
+ dropOnRoot(draggedPaths: readonly string[]): void;
50
+ }
51
+
52
+ /**
53
+ * The from→to moves a drop performs: each dragged path keeps its
54
+ * basename under the target directory. Paths already directly inside
55
+ * the target are skipped.
56
+ */
57
+ export function computeDropMoves(context: FileTreeDropContext): IDropMove[] {
58
+ const dir = context.target.directoryPath ?? ROOT_LOAD_KEY;
59
+ return context.draggedPaths
60
+ .filter(path => parentOf(path) !== dir)
61
+ .map(path => ({ from: path, to: `${dir}${canonicalBasename(path)}` }));
62
+ }
63
+
64
+ const ROOT_DROP_TARGET: FileTreeDropTarget = {
65
+ directoryPath: null,
66
+ flattenedSegmentPath: null,
67
+ hoveredPath: null,
68
+ kind: 'root'
69
+ };
70
+
71
+ /**
72
+ * The moves for a drop of `paths` onto the workspace root.
73
+ */
74
+ export function computeRootDropMoves(paths: readonly string[]): IDropMove[] {
75
+ return computeDropMoves({ draggedPaths: paths, target: ROOT_DROP_TARGET });
76
+ }
77
+
78
+ /**
79
+ * Build the `dragAndDrop` option for `useFileTree`. The tree captures
80
+ * its options once, so the callbacks delegate through `handlerRef`,
81
+ * filled by the contents-sync effect. `canDrop` hides the drop
82
+ * highlight for all-no-op drops, which the library would accept.
83
+ */
84
+ export function createTreeDragAndDropConfig(
85
+ handlerRef: React.RefObject<ITreeDropHandler | null>
86
+ ): FileTreeDragAndDropConfig {
87
+ return {
88
+ canDrop: context => computeDropMoves(context).length > 0,
89
+ onDropComplete: result => {
90
+ handlerRef.current?.completeDrop(result);
91
+ },
92
+ onDropError: (error, context) => {
93
+ handlerRef.current?.failedDrop(error, context);
94
+ }
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Options for {@link useRootDropZone}.
100
+ */
101
+ interface IRootDropZoneOptions {
102
+ /**
103
+ * The tree model, queried for the selection at drag start.
104
+ */
105
+ model: FileTree;
106
+ /**
107
+ * The drop handler ref, filled by the contents-sync effect.
108
+ */
109
+ handlerRef: React.RefObject<ITreeDropHandler | null>;
110
+ /**
111
+ * The light-DOM wrapper around the tree host; composed drag events
112
+ * bubble out of the shadow root to it.
113
+ */
114
+ wrapperRef: React.RefObject<HTMLDivElement | null>;
115
+ }
116
+
117
+ /**
118
+ * Accept drops on the empty space below the last row as moves to the
119
+ * workspace root — the tree resolves a drop target only while the cursor
120
+ * is over a row and silently discards such drops.
121
+ */
122
+ export function useRootDropZone(options: IRootDropZoneOptions): void {
123
+ const { model, handlerRef, wrapperRef } = options;
124
+
125
+ React.useEffect(() => {
126
+ const wrapper = wrapperRef.current;
127
+ if (wrapper === null) {
128
+ return;
129
+ }
130
+
131
+ let draggedPaths: readonly string[] | null = null;
132
+
133
+ const findRow = (event: DragEvent): HTMLElement | null => {
134
+ for (const target of event.composedPath()) {
135
+ if (target instanceof HTMLElement && target.dataset.type === 'item') {
136
+ return target;
137
+ }
138
+ }
139
+ return null;
140
+ };
141
+
142
+ const handleDragStart = (event: DragEvent): void => {
143
+ draggedPaths = null;
144
+ // The tree cancels dragstart when it refuses a session, e.g.
145
+ // while the filter is open.
146
+ if (event.defaultPrevented) {
147
+ return;
148
+ }
149
+ const path = findRow(event)?.dataset.itemPath;
150
+ if (path === undefined || path.length === 0) {
151
+ return;
152
+ }
153
+ // The selection is the dragged set (the tree selects the pressed
154
+ // row); entries nested under a dragged folder travel with it.
155
+ const selection = model.getSelectedPaths();
156
+ const candidates = selection.includes(path) ? selection : [path];
157
+ const folders = candidates.filter(c => c.endsWith('/'));
158
+ draggedPaths = candidates.filter(
159
+ c => !folders.some(folder => folder !== c && c.startsWith(folder))
160
+ );
161
+ };
162
+
163
+ const handleDrop = (event: DragEvent): void => {
164
+ const paths = draggedPaths;
165
+ draggedPaths = null;
166
+ // Drops on a row were already resolved by the tree itself.
167
+ if (paths === null || findRow(event) !== null) {
168
+ return;
169
+ }
170
+ event.preventDefault();
171
+ handlerRef.current?.dropOnRoot(paths);
172
+ };
173
+
174
+ const handleDragEnd = (): void => {
175
+ draggedPaths = null;
176
+ };
177
+
178
+ wrapper.addEventListener('dragstart', handleDragStart);
179
+ wrapper.addEventListener('drop', handleDrop);
180
+ window.addEventListener('dragend', handleDragEnd);
181
+ return () => {
182
+ wrapper.removeEventListener('dragstart', handleDragStart);
183
+ wrapper.removeEventListener('drop', handleDrop);
184
+ window.removeEventListener('dragend', handleDragEnd);
185
+ draggedPaths = null;
186
+ };
187
+ }, [model, handlerRef, wrapperRef]);
188
+ }