@plmbr/notebook-intelligence 5.0.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.
- package/LICENSE +674 -0
- package/README.md +412 -0
- package/lib/api.d.ts +288 -0
- package/lib/api.js +927 -0
- package/lib/cell-output-bundle.d.ts +25 -0
- package/lib/cell-output-bundle.js +129 -0
- package/lib/cell-output-toolbar.d.ts +26 -0
- package/lib/cell-output-toolbar.js +188 -0
- package/lib/chat-progress-feedback.d.ts +3 -0
- package/lib/chat-progress-feedback.js +27 -0
- package/lib/chat-sidebar.d.ts +92 -0
- package/lib/chat-sidebar.js +3452 -0
- package/lib/command-ids.d.ts +39 -0
- package/lib/command-ids.js +44 -0
- package/lib/components/ask-user-question.d.ts +2 -0
- package/lib/components/ask-user-question.js +85 -0
- package/lib/components/checkbox.d.ts +2 -0
- package/lib/components/checkbox.js +30 -0
- package/lib/components/claude-mcp-panel.d.ts +2 -0
- package/lib/components/claude-mcp-panel.js +275 -0
- package/lib/components/claude-mcp-paste.d.ts +7 -0
- package/lib/components/claude-mcp-paste.js +104 -0
- package/lib/components/claude-session-picker.d.ts +8 -0
- package/lib/components/claude-session-picker.js +127 -0
- package/lib/components/form-dialog.d.ts +25 -0
- package/lib/components/form-dialog.js +35 -0
- package/lib/components/launcher-picker.d.ts +6 -0
- package/lib/components/launcher-picker.js +135 -0
- package/lib/components/mcp-util.d.ts +2 -0
- package/lib/components/mcp-util.js +37 -0
- package/lib/components/notebook-generation-popover.d.ts +7 -0
- package/lib/components/notebook-generation-popover.js +60 -0
- package/lib/components/pill.d.ts +2 -0
- package/lib/components/pill.js +5 -0
- package/lib/components/plugins-panel.d.ts +3 -0
- package/lib/components/plugins-panel.js +466 -0
- package/lib/components/settings-panel.d.ts +11 -0
- package/lib/components/settings-panel.js +742 -0
- package/lib/components/skills-panel.d.ts +2 -0
- package/lib/components/skills-panel.js +1264 -0
- package/lib/handler.d.ts +8 -0
- package/lib/handler.js +36 -0
- package/lib/icons.d.ts +45 -0
- package/lib/icons.js +54 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +2079 -0
- package/lib/markdown-renderer.d.ts +10 -0
- package/lib/markdown-renderer.js +64 -0
- package/lib/notebook-generation-toolbar.d.ts +16 -0
- package/lib/notebook-generation-toolbar.js +197 -0
- package/lib/notebook-generation.d.ts +8 -0
- package/lib/notebook-generation.js +12 -0
- package/lib/open-file-refresh-watcher-env.d.ts +4 -0
- package/lib/open-file-refresh-watcher-env.js +33 -0
- package/lib/open-file-refresh-watcher.d.ts +97 -0
- package/lib/open-file-refresh-watcher.js +190 -0
- package/lib/shell-utils.d.ts +6 -0
- package/lib/shell-utils.js +9 -0
- package/lib/task-target-notebook.d.ts +2 -0
- package/lib/task-target-notebook.js +28 -0
- package/lib/terminal-drag-format.d.ts +9 -0
- package/lib/terminal-drag-format.js +23 -0
- package/lib/terminal-drag.d.ts +12 -0
- package/lib/terminal-drag.js +268 -0
- package/lib/tokens.d.ts +149 -0
- package/lib/tokens.js +88 -0
- package/lib/tour/tour-anchors.d.ts +18 -0
- package/lib/tour/tour-anchors.js +18 -0
- package/lib/tour/tour-config.d.ts +66 -0
- package/lib/tour/tour-config.js +99 -0
- package/lib/tour/tour-defaults.json +58 -0
- package/lib/tour/tour-events.d.ts +19 -0
- package/lib/tour/tour-events.js +30 -0
- package/lib/tour/tour-overlay.d.ts +6 -0
- package/lib/tour/tour-overlay.js +350 -0
- package/lib/tour/tour-state.d.ts +20 -0
- package/lib/tour/tour-state.js +81 -0
- package/lib/tour/tour-steps.d.ts +33 -0
- package/lib/tour/tour-steps.js +216 -0
- package/lib/utils.d.ts +53 -0
- package/lib/utils.js +385 -0
- package/package.json +258 -0
- package/schema/plugin.json +42 -0
- package/src/api.ts +1424 -0
- package/src/cell-output-bundle.ts +176 -0
- package/src/cell-output-toolbar.ts +232 -0
- package/src/chat-progress-feedback.ts +35 -0
- package/src/chat-sidebar.tsx +5147 -0
- package/src/command-ids.ts +67 -0
- package/src/components/ask-user-question.tsx +151 -0
- package/src/components/checkbox.tsx +62 -0
- package/src/components/claude-mcp-panel.tsx +543 -0
- package/src/components/claude-mcp-paste.ts +132 -0
- package/src/components/claude-session-picker.tsx +214 -0
- package/src/components/form-dialog.tsx +75 -0
- package/src/components/launcher-picker.tsx +237 -0
- package/src/components/mcp-util.ts +53 -0
- package/src/components/notebook-generation-popover.tsx +127 -0
- package/src/components/pill.tsx +15 -0
- package/src/components/plugins-panel.tsx +774 -0
- package/src/components/settings-panel.tsx +1631 -0
- package/src/components/skills-panel.tsx +2084 -0
- package/src/handler.ts +51 -0
- package/src/icons.ts +71 -0
- package/src/index.ts +2583 -0
- package/src/markdown-renderer.tsx +153 -0
- package/src/notebook-generation-toolbar.tsx +281 -0
- package/src/notebook-generation.ts +23 -0
- package/src/open-file-refresh-watcher-env.ts +52 -0
- package/src/open-file-refresh-watcher.ts +260 -0
- package/src/shell-utils.ts +10 -0
- package/src/svg.d.ts +4 -0
- package/src/task-target-notebook.ts +37 -0
- package/src/terminal-drag-format.ts +29 -0
- package/src/terminal-drag.ts +382 -0
- package/src/tokens.ts +171 -0
- package/src/tour/tour-anchors.ts +21 -0
- package/src/tour/tour-config.ts +160 -0
- package/src/tour/tour-events.ts +34 -0
- package/src/tour/tour-overlay.tsx +474 -0
- package/src/tour/tour-state.ts +87 -0
- package/src/tour/tour-steps.ts +281 -0
- package/src/utils.ts +455 -0
- package/style/base.css +3238 -0
- package/style/icons/cell-toolbar-bug.svg +5 -0
- package/style/icons/cell-toolbar-chat.svg +5 -0
- package/style/icons/cell-toolbar-sparkle.svg +5 -0
- package/style/icons/claude.svg +1 -0
- package/style/icons/copilot-warning.svg +1 -0
- package/style/icons/copilot.svg +1 -0
- package/style/icons/copy.svg +1 -0
- package/style/icons/openai.svg +1 -0
- package/style/icons/opencode.svg +1 -0
- package/style/icons/sparkles-warning.svg +5 -0
- package/style/icons/sparkles.svg +1 -0
- package/style/index.css +1 -0
- package/style/index.js +1 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
|
|
2
|
+
import { CommandIDs } from './command-ids';
|
|
3
|
+
// Cell-targeting commands accept an optional `notebookPath` to bypass
|
|
4
|
+
// `app.shell.currentWidget`. When the agent runs a task and the user
|
|
5
|
+
// switches tabs mid-run, the previously-active notebook is no longer the
|
|
6
|
+
// focused widget; the chat sidebar injects the captured task-target path
|
|
7
|
+
// into args for these command IDs so cell ops resolve against the right
|
|
8
|
+
// notebook (issue #252). Built from `CommandIDs` so a rename on either
|
|
9
|
+
// side is caught at compile time.
|
|
10
|
+
export const NOTEBOOK_TARGETED_COMMAND_IDS = new Set([
|
|
11
|
+
CommandIDs.addMarkdownCellToActiveNotebook,
|
|
12
|
+
CommandIDs.addCodeCellToActiveNotebook,
|
|
13
|
+
CommandIDs.getCellTypeAndSource,
|
|
14
|
+
CommandIDs.setCellTypeAndSource,
|
|
15
|
+
CommandIDs.getNumberOfCells,
|
|
16
|
+
CommandIDs.getCellOutput,
|
|
17
|
+
CommandIDs.insertCellAtIndex,
|
|
18
|
+
CommandIDs.deleteCellAtIndex,
|
|
19
|
+
CommandIDs.runCellAtIndex
|
|
20
|
+
]);
|
|
21
|
+
export function injectTaskTargetNotebook(commandId, args, taskTargetPath) {
|
|
22
|
+
if (!taskTargetPath ||
|
|
23
|
+
!NOTEBOOK_TARGETED_COMMAND_IDS.has(commandId) ||
|
|
24
|
+
(args && args.notebookPath)) {
|
|
25
|
+
return args;
|
|
26
|
+
}
|
|
27
|
+
return { ...(args !== null && args !== void 0 ? args : {}), notebookPath: taskTargetPath };
|
|
28
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type DragMode = 'mention' | 'raw';
|
|
2
|
+
/**
|
|
3
|
+
* Format a list of paths for injection per mode. @-mention prefixes each
|
|
4
|
+
* path with "@" (Claude Code syntax, no quoting); raw mode shell-escapes
|
|
5
|
+
* absolute paths for non-Claude shell sessions. Single-space separator
|
|
6
|
+
* is intentional; the trailing space is appended by the caller.
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatForMode(paths: string[], mode: DragMode): string;
|
|
9
|
+
export declare function invertMode(mode: DragMode, shouldInvert: boolean): DragMode;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
|
|
2
|
+
// Pure helpers extracted from `terminal-drag.ts` so they can be unit
|
|
3
|
+
// tested without JupyterLab / Lumino imports (which pull DOM globals
|
|
4
|
+
// that jsdom doesn't provide, like DragEvent).
|
|
5
|
+
import { shellSingleQuote } from './shell-utils';
|
|
6
|
+
/**
|
|
7
|
+
* Format a list of paths for injection per mode. @-mention prefixes each
|
|
8
|
+
* path with "@" (Claude Code syntax, no quoting); raw mode shell-escapes
|
|
9
|
+
* absolute paths for non-Claude shell sessions. Single-space separator
|
|
10
|
+
* is intentional; the trailing space is appended by the caller.
|
|
11
|
+
*/
|
|
12
|
+
export function formatForMode(paths, mode) {
|
|
13
|
+
if (mode === 'mention') {
|
|
14
|
+
return paths.map(p => `@${p}`).join(' ');
|
|
15
|
+
}
|
|
16
|
+
return paths.map(shellSingleQuote).join(' ');
|
|
17
|
+
}
|
|
18
|
+
export function invertMode(mode, shouldInvert) {
|
|
19
|
+
if (!shouldInvert) {
|
|
20
|
+
return mode;
|
|
21
|
+
}
|
|
22
|
+
return mode === 'mention' ? 'raw' : 'mention';
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type { DragMode } from './terminal-drag-format';
|
|
2
|
+
export { formatForMode, invertMode } from './terminal-drag-format';
|
|
3
|
+
export interface ITerminalDragOptions {
|
|
4
|
+
tracker: unknown;
|
|
5
|
+
/**
|
|
6
|
+
* Re-evaluated on each event so flipping the admin policy at runtime
|
|
7
|
+
* (e.g. force-off via env at next reload) takes effect on listeners
|
|
8
|
+
* that are already wired without needing to tear them down.
|
|
9
|
+
*/
|
|
10
|
+
isEnabled: () => boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function attachTerminalDragDrop(options: ITerminalDragOptions): void;
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
// Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
|
|
2
|
+
import { Notification } from '@jupyterlab/apputils';
|
|
3
|
+
import { Widget } from '@lumino/widgets';
|
|
4
|
+
import { NBIAPI } from './api';
|
|
5
|
+
import { formatForMode, invertMode } from './terminal-drag-format';
|
|
6
|
+
export { formatForMode, invertMode } from './terminal-drag-format';
|
|
7
|
+
// File-browser drag dispatches a Lumino lm-drop event carrying paths
|
|
8
|
+
// under this MIME (see node_modules/@jupyterlab/filebrowser/lib/listing.js).
|
|
9
|
+
const FILE_BROWSER_MIME = 'application/x-jupyter-icontents';
|
|
10
|
+
const DRAG_OVER_CLASS = 'nbi-terminal-drag-over';
|
|
11
|
+
const TOOLBAR_BUTTON_CLASS = 'nbi-terminal-drag-mode-button';
|
|
12
|
+
const widgetState = new WeakMap();
|
|
13
|
+
export function attachTerminalDragDrop(options) {
|
|
14
|
+
const tracker = options.tracker;
|
|
15
|
+
const { isEnabled } = options;
|
|
16
|
+
const wire = (widget) => {
|
|
17
|
+
if (widgetState.has(widget)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
setupTerminal(widget, isEnabled);
|
|
21
|
+
};
|
|
22
|
+
tracker.forEach(wire);
|
|
23
|
+
tracker.widgetAdded.connect((_, widget) => wire(widget));
|
|
24
|
+
}
|
|
25
|
+
function setupTerminal(widget, isEnabled) {
|
|
26
|
+
const host = widget.node;
|
|
27
|
+
const state = {
|
|
28
|
+
mode: 'mention',
|
|
29
|
+
dragDepth: 0,
|
|
30
|
+
cleanup: () => { }
|
|
31
|
+
};
|
|
32
|
+
const inject = (paths, shiftHeld) => {
|
|
33
|
+
var _a;
|
|
34
|
+
if (paths.length === 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Async upload paths can finish after the terminal is closed; calling
|
|
38
|
+
// paste on a disposed Lumino Widget throws.
|
|
39
|
+
if (widget.isDisposed) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const effectiveMode = invertMode(state.mode, shiftHeld);
|
|
43
|
+
widget.content.paste(`${formatForMode(paths, effectiveMode)} `);
|
|
44
|
+
// Activate the outer MainAreaWidget so the terminal also gets raised
|
|
45
|
+
// if it's a background tab in a split. Otherwise the next keystroke
|
|
46
|
+
// goes to the file-browser (Enter would "open the selected file") or
|
|
47
|
+
// to whichever surface held focus before the drag.
|
|
48
|
+
(_a = widget.activate) === null || _a === void 0 ? void 0 : _a.call(widget);
|
|
49
|
+
};
|
|
50
|
+
const handleDragEnter = (event) => {
|
|
51
|
+
if (!isEnabled() || !event.dataTransfer) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!event.dataTransfer.types.includes('Files')) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
state.dragDepth += 1;
|
|
58
|
+
host.classList.add(DRAG_OVER_CLASS);
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
event.stopImmediatePropagation();
|
|
61
|
+
};
|
|
62
|
+
const handleDragOver = (event) => {
|
|
63
|
+
if (!isEnabled() || !event.dataTransfer) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!event.dataTransfer.types.includes('Files')) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
event.stopImmediatePropagation();
|
|
71
|
+
event.dataTransfer.dropEffect = 'copy';
|
|
72
|
+
};
|
|
73
|
+
const handleDragLeave = (event) => {
|
|
74
|
+
if (!isEnabled()) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
state.dragDepth = Math.max(0, state.dragDepth - 1);
|
|
78
|
+
if (state.dragDepth === 0) {
|
|
79
|
+
host.classList.remove(DRAG_OVER_CLASS);
|
|
80
|
+
}
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
event.stopImmediatePropagation();
|
|
83
|
+
};
|
|
84
|
+
const handleDrop = (event) => {
|
|
85
|
+
if (!isEnabled()) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
state.dragDepth = 0;
|
|
89
|
+
host.classList.remove(DRAG_OVER_CLASS);
|
|
90
|
+
if (!event.dataTransfer) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const files = Array.from(event.dataTransfer.files);
|
|
94
|
+
if (files.length === 0) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
event.preventDefault();
|
|
98
|
+
event.stopImmediatePropagation();
|
|
99
|
+
const shiftHeld = event.shiftKey;
|
|
100
|
+
void uploadAndInject(files, shiftHeld, inject);
|
|
101
|
+
};
|
|
102
|
+
// Lumino dispatches lm-* events on the deepest DOM element under the
|
|
103
|
+
// cursor. Listening on `host` would in theory catch the bubble, but
|
|
104
|
+
// intermediate widgets (e.g. xterm's viewport) can call
|
|
105
|
+
// stopPropagation in a target-phase handler before we see it. Listening
|
|
106
|
+
// at the document level with a containment check is the most reliable
|
|
107
|
+
// way to observe a drop that's geometrically inside this terminal.
|
|
108
|
+
const isInsideHost = (event) => {
|
|
109
|
+
const target = event.target;
|
|
110
|
+
return target instanceof Node && host.contains(target);
|
|
111
|
+
};
|
|
112
|
+
const handleLuminoDragEnter = (event) => {
|
|
113
|
+
if (!isEnabled() || !hasFileBrowserPaths(event) || !isInsideHost(event)) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
state.dragDepth += 1;
|
|
117
|
+
host.classList.add(DRAG_OVER_CLASS);
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
event.stopPropagation();
|
|
120
|
+
};
|
|
121
|
+
const handleLuminoDragOver = (event) => {
|
|
122
|
+
if (!isEnabled() || !hasFileBrowserPaths(event) || !isInsideHost(event)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
event.stopPropagation();
|
|
127
|
+
// Echo the source's proposedAction back as dropAction. The file
|
|
128
|
+
// browser starts its Drag with supportedActions: 'move', so a
|
|
129
|
+
// hardcoded 'copy' falls through validateAction to 'none' and
|
|
130
|
+
// Lumino skips lm-drop on pointerup. Mirroring proposedAction keeps
|
|
131
|
+
// us inside whatever the source supports.
|
|
132
|
+
const dragEvent = event;
|
|
133
|
+
dragEvent.dropAction = dragEvent.proposedAction || 'move';
|
|
134
|
+
};
|
|
135
|
+
const handleLuminoDragLeave = (event) => {
|
|
136
|
+
if (!isEnabled() || !isInsideHost(event)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
state.dragDepth = Math.max(0, state.dragDepth - 1);
|
|
140
|
+
if (state.dragDepth === 0) {
|
|
141
|
+
host.classList.remove(DRAG_OVER_CLASS);
|
|
142
|
+
}
|
|
143
|
+
event.preventDefault();
|
|
144
|
+
event.stopPropagation();
|
|
145
|
+
};
|
|
146
|
+
const handleLuminoDrop = (event) => {
|
|
147
|
+
if (!isEnabled() || !hasFileBrowserPaths(event) || !isInsideHost(event)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const dragEvent = event;
|
|
151
|
+
const paths = dragEvent.mimeData.getData(FILE_BROWSER_MIME);
|
|
152
|
+
if (!Array.isArray(paths) || paths.length === 0) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
event.stopPropagation();
|
|
157
|
+
dragEvent.dropAction = dragEvent.proposedAction || 'move';
|
|
158
|
+
state.dragDepth = 0;
|
|
159
|
+
host.classList.remove(DRAG_OVER_CLASS);
|
|
160
|
+
inject(paths.filter((p) => typeof p === 'string'), dragEvent.shiftKey);
|
|
161
|
+
};
|
|
162
|
+
host.addEventListener('dragenter', handleDragEnter, true);
|
|
163
|
+
host.addEventListener('dragover', handleDragOver, true);
|
|
164
|
+
host.addEventListener('dragleave', handleDragLeave, true);
|
|
165
|
+
host.addEventListener('drop', handleDrop, true);
|
|
166
|
+
// lm-* listeners go on the document (capture phase) so we observe
|
|
167
|
+
// them before any intermediate widget can stopPropagation. The
|
|
168
|
+
// containment check filters to events whose target is inside this
|
|
169
|
+
// terminal's host node.
|
|
170
|
+
document.addEventListener('lm-dragenter', handleLuminoDragEnter, true);
|
|
171
|
+
document.addEventListener('lm-dragover', handleLuminoDragOver, true);
|
|
172
|
+
document.addEventListener('lm-dragleave', handleLuminoDragLeave, true);
|
|
173
|
+
document.addEventListener('lm-drop', handleLuminoDrop, true);
|
|
174
|
+
const button = new TerminalDragModeButton('mention', () => {
|
|
175
|
+
state.mode = state.mode === 'mention' ? 'raw' : 'mention';
|
|
176
|
+
button.setMode(state.mode);
|
|
177
|
+
});
|
|
178
|
+
widget.toolbar.addItem('nbi-terminal-drag-mode', button);
|
|
179
|
+
state.cleanup = () => {
|
|
180
|
+
host.removeEventListener('dragenter', handleDragEnter, true);
|
|
181
|
+
host.removeEventListener('dragover', handleDragOver, true);
|
|
182
|
+
host.removeEventListener('dragleave', handleDragLeave, true);
|
|
183
|
+
host.removeEventListener('drop', handleDrop, true);
|
|
184
|
+
document.removeEventListener('lm-dragenter', handleLuminoDragEnter, true);
|
|
185
|
+
document.removeEventListener('lm-dragover', handleLuminoDragOver, true);
|
|
186
|
+
document.removeEventListener('lm-dragleave', handleLuminoDragLeave, true);
|
|
187
|
+
document.removeEventListener('lm-drop', handleLuminoDrop, true);
|
|
188
|
+
};
|
|
189
|
+
widget.disposed.connect(() => {
|
|
190
|
+
state.cleanup();
|
|
191
|
+
widgetState.delete(widget);
|
|
192
|
+
});
|
|
193
|
+
widgetState.set(widget, state);
|
|
194
|
+
}
|
|
195
|
+
function hasFileBrowserPaths(event) {
|
|
196
|
+
var _a;
|
|
197
|
+
const mimeData = event.mimeData;
|
|
198
|
+
return ((_a = mimeData === null || mimeData === void 0 ? void 0 : mimeData.hasData) === null || _a === void 0 ? void 0 : _a.call(mimeData, FILE_BROWSER_MIME)) === true;
|
|
199
|
+
}
|
|
200
|
+
async function uploadAndInject(files, shiftHeld, inject) {
|
|
201
|
+
const results = await Promise.allSettled(files.map(f => NBIAPI.uploadFile(f)));
|
|
202
|
+
const paths = [];
|
|
203
|
+
const failures = [];
|
|
204
|
+
results.forEach((result, index) => {
|
|
205
|
+
const file = files[index];
|
|
206
|
+
if (result.status === 'fulfilled') {
|
|
207
|
+
paths.push(result.value.serverPath);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
failures.push({
|
|
211
|
+
name: file.name,
|
|
212
|
+
reason: describeUploadError(result.reason)
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
if (failures.length > 0) {
|
|
216
|
+
// Inline in the toast so the user sees both what failed and why
|
|
217
|
+
// (e.g. 413 from the size cap). Truncated to 3 entries; rest collapsed
|
|
218
|
+
// into a "+ N more" footer to fit JL's 140-char notification limit.
|
|
219
|
+
const head = failures
|
|
220
|
+
.slice(0, 3)
|
|
221
|
+
.map(f => `${f.name}: ${f.reason}`)
|
|
222
|
+
.join('; ');
|
|
223
|
+
const tail = failures.length > 3 ? ` (+${failures.length - 3} more)` : '';
|
|
224
|
+
Notification.error(`Terminal drop upload failed for ${head}${tail}`);
|
|
225
|
+
}
|
|
226
|
+
inject(paths, shiftHeld);
|
|
227
|
+
}
|
|
228
|
+
function describeUploadError(reason) {
|
|
229
|
+
if (reason && typeof reason === 'object') {
|
|
230
|
+
const r = reason;
|
|
231
|
+
if (typeof r.message === 'string' && r.message.trim().length > 0) {
|
|
232
|
+
return r.message;
|
|
233
|
+
}
|
|
234
|
+
if (r.response && typeof r.response.status === 'number') {
|
|
235
|
+
return `HTTP ${r.response.status}`;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return String(reason);
|
|
239
|
+
}
|
|
240
|
+
class TerminalDragModeButton extends Widget {
|
|
241
|
+
constructor(initialMode, onToggle) {
|
|
242
|
+
super();
|
|
243
|
+
this.addClass('jp-Toolbar-item');
|
|
244
|
+
this.addClass(TOOLBAR_BUTTON_CLASS);
|
|
245
|
+
this._onToggle = onToggle;
|
|
246
|
+
this._button = document.createElement('button');
|
|
247
|
+
this._button.type = 'button';
|
|
248
|
+
this._button.classList.add('jp-ToolbarButtonComponent');
|
|
249
|
+
this._button.classList.add(`${TOOLBAR_BUTTON_CLASS}-toggle`);
|
|
250
|
+
this._button.addEventListener('click', () => this._onToggle());
|
|
251
|
+
this.node.appendChild(this._button);
|
|
252
|
+
this.setMode(initialMode);
|
|
253
|
+
}
|
|
254
|
+
setMode(mode) {
|
|
255
|
+
const isMention = mode === 'mention';
|
|
256
|
+
this._button.textContent = isMention ? '@' : '/';
|
|
257
|
+
this._button.setAttribute('aria-pressed', isMention ? 'false' : 'true');
|
|
258
|
+
// aria-label carries the full mode + Shift-modifier explanation;
|
|
259
|
+
// title is a short hover-tip so screen readers don't double-announce
|
|
260
|
+
// the same string from both attributes.
|
|
261
|
+
this._button.setAttribute('aria-label', isMention
|
|
262
|
+
? 'Terminal drop inserts @-mention paths. Click to switch to raw path mode. Hold Shift while dropping to invert for one drop.'
|
|
263
|
+
: 'Terminal drop inserts raw, shell-escaped absolute paths. Click to switch to @-mention mode. Hold Shift while dropping to invert for one drop.');
|
|
264
|
+
this._button.title = isMention
|
|
265
|
+
? 'Drop mode: @-mention'
|
|
266
|
+
: 'Drop mode: raw path';
|
|
267
|
+
}
|
|
268
|
+
}
|
package/lib/tokens.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Widget } from '@lumino/widgets';
|
|
2
|
+
import { CodeEditor } from '@jupyterlab/codeeditor';
|
|
3
|
+
import { Token } from '@lumino/coreutils';
|
|
4
|
+
export interface IActiveDocumentInfo {
|
|
5
|
+
activeWidget: Widget | null;
|
|
6
|
+
language: string;
|
|
7
|
+
filename: string;
|
|
8
|
+
filePath: string;
|
|
9
|
+
activeCellIndex: number;
|
|
10
|
+
selection?: CodeEditor.IRange;
|
|
11
|
+
}
|
|
12
|
+
export interface IChatCompletionResponseEmitter {
|
|
13
|
+
emit: (response: any) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare enum RequestDataType {
|
|
16
|
+
ChatRequest = "chat-request",
|
|
17
|
+
ChatUserInput = "chat-user-input",
|
|
18
|
+
ClearChatHistory = "clear-chat-history",
|
|
19
|
+
RunUICommandResponse = "run-ui-command-response",
|
|
20
|
+
GenerateCode = "generate-code",
|
|
21
|
+
CancelChatRequest = "cancel-chat-request",
|
|
22
|
+
InlineCompletionRequest = "inline-completion-request",
|
|
23
|
+
CancelInlineCompletionRequest = "cancel-inline-completion-request"
|
|
24
|
+
}
|
|
25
|
+
export declare enum BackendMessageType {
|
|
26
|
+
StreamMessage = "stream-message",
|
|
27
|
+
StreamEnd = "stream-end",
|
|
28
|
+
RunUICommand = "run-ui-command",
|
|
29
|
+
GitHubCopilotLoginStatusChange = "github-copilot-login-status-change",
|
|
30
|
+
MCPServerStatusChange = "mcp-server-status-change",
|
|
31
|
+
ClaudeCodeStatusChange = "claude-code-status-change",
|
|
32
|
+
ClaudeCodeHeartbeat = "claude-code-heartbeat",
|
|
33
|
+
SkillsReloaded = "skills-reloaded"
|
|
34
|
+
}
|
|
35
|
+
export declare enum ResponseStreamDataType {
|
|
36
|
+
LLMRaw = "llm-raw",
|
|
37
|
+
Markdown = "markdown",
|
|
38
|
+
MarkdownPart = "markdown-part",
|
|
39
|
+
Image = "image",
|
|
40
|
+
HTMLFrame = "html-frame",
|
|
41
|
+
Button = "button",
|
|
42
|
+
Anchor = "anchor",
|
|
43
|
+
Progress = "progress",
|
|
44
|
+
Confirmation = "confirmation",
|
|
45
|
+
AskUserQuestion = "ask-user-question"
|
|
46
|
+
}
|
|
47
|
+
export declare enum ContextType {
|
|
48
|
+
Custom = "custom",
|
|
49
|
+
CurrentFile = "current-file",
|
|
50
|
+
OutputContext = "output-context"
|
|
51
|
+
}
|
|
52
|
+
export interface IOutputContextItem {
|
|
53
|
+
cellSource: string;
|
|
54
|
+
mimeBundles: {
|
|
55
|
+
mimeType: string;
|
|
56
|
+
data: string;
|
|
57
|
+
sizeTokens: number;
|
|
58
|
+
}[];
|
|
59
|
+
isError: boolean;
|
|
60
|
+
truncated: boolean;
|
|
61
|
+
}
|
|
62
|
+
export declare enum MCPServerStatus {
|
|
63
|
+
NotConnected = "not-connected",
|
|
64
|
+
Connecting = "connecting",
|
|
65
|
+
Disconnecting = "disconnecting",
|
|
66
|
+
FailedToConnect = "failed-to-connect",
|
|
67
|
+
Connected = "connected",
|
|
68
|
+
UpdatingToolList = "updating-tool-list",
|
|
69
|
+
UpdatedToolList = "updated-tool-list",
|
|
70
|
+
UpdatingPromptList = "updating-prompt-list",
|
|
71
|
+
UpdatedPromptList = "updated-prompt-list"
|
|
72
|
+
}
|
|
73
|
+
export interface IContextItem {
|
|
74
|
+
type: ContextType;
|
|
75
|
+
content: string;
|
|
76
|
+
currentCellContents: ICellContents;
|
|
77
|
+
filePath?: string;
|
|
78
|
+
cellIndex?: number;
|
|
79
|
+
startLine?: number;
|
|
80
|
+
endLine?: number;
|
|
81
|
+
isImage?: boolean;
|
|
82
|
+
mimeType?: string;
|
|
83
|
+
outputContext?: IOutputContextItem;
|
|
84
|
+
}
|
|
85
|
+
export interface ICellContents {
|
|
86
|
+
input: string;
|
|
87
|
+
output: string;
|
|
88
|
+
}
|
|
89
|
+
export interface IChatParticipant {
|
|
90
|
+
id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
description: string;
|
|
93
|
+
iconPath: string;
|
|
94
|
+
commands: string[];
|
|
95
|
+
}
|
|
96
|
+
export interface IToolSelections {
|
|
97
|
+
builtinToolsets?: string[];
|
|
98
|
+
mcpServers?: {
|
|
99
|
+
[key: string]: string[];
|
|
100
|
+
};
|
|
101
|
+
extensions?: {
|
|
102
|
+
[key: string]: string[];
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export declare enum BuiltinToolsetType {
|
|
106
|
+
NotebookEdit = "nbi-notebook-edit",
|
|
107
|
+
NotebookExecute = "nbi-notebook-execute",
|
|
108
|
+
PythonFileEdit = "nbi-python-file-edit",
|
|
109
|
+
FileEdit = "nbi-file-edit",
|
|
110
|
+
FileRead = "nbi-file-read",
|
|
111
|
+
CommandExecute = "nbi-command-execute"
|
|
112
|
+
}
|
|
113
|
+
export declare const GITHUB_COPILOT_PROVIDER_ID = "github-copilot";
|
|
114
|
+
export declare const CLAUDE_CODE_CHAT_PARTICIPANT_ID = "claude-code";
|
|
115
|
+
export declare enum AssistantMode {
|
|
116
|
+
Default = "default",
|
|
117
|
+
Claude = "claude"
|
|
118
|
+
}
|
|
119
|
+
export declare enum TelemetryEventType {
|
|
120
|
+
InlineCompletionRequest = "inline-completion-request",
|
|
121
|
+
ExplainThisRequest = "explain-this-request",
|
|
122
|
+
FixThisCodeRequest = "fix-this-code-request",
|
|
123
|
+
ExplainThisOutputRequest = "explain-this-output-request",
|
|
124
|
+
TroubleshootThisOutputRequest = "troubleshoot-this-output-request",
|
|
125
|
+
OutputFollowUpRequest = "output-follow-up-request",
|
|
126
|
+
GenerateCodeRequest = "generate-code-request",
|
|
127
|
+
ChatRequest = "chat-request",
|
|
128
|
+
InlineChatRequest = "inline-chat-request",
|
|
129
|
+
ChatResponse = "chat-response",
|
|
130
|
+
InlineChatResponse = "inline-chat-response",
|
|
131
|
+
InlineCompletionResponse = "inline-completion-response",
|
|
132
|
+
Feedback = "feedback"
|
|
133
|
+
}
|
|
134
|
+
export interface ITelemetryEvent {
|
|
135
|
+
type: TelemetryEventType;
|
|
136
|
+
data?: any;
|
|
137
|
+
}
|
|
138
|
+
export interface ITelemetryListener {
|
|
139
|
+
get name(): string;
|
|
140
|
+
onTelemetryEvent: (event: ITelemetryEvent) => void;
|
|
141
|
+
}
|
|
142
|
+
export interface ITelemetryEmitter {
|
|
143
|
+
emitTelemetryEvent(event: ITelemetryEvent): void;
|
|
144
|
+
}
|
|
145
|
+
export declare const INotebookIntelligence: Token<INotebookIntelligence>;
|
|
146
|
+
export interface INotebookIntelligence {
|
|
147
|
+
registerTelemetryListener: (listener: ITelemetryListener) => void;
|
|
148
|
+
unregisterTelemetryListener: (listener: ITelemetryListener) => void;
|
|
149
|
+
}
|
package/lib/tokens.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
|
|
2
|
+
import { Token } from '@lumino/coreutils';
|
|
3
|
+
export var RequestDataType;
|
|
4
|
+
(function (RequestDataType) {
|
|
5
|
+
RequestDataType["ChatRequest"] = "chat-request";
|
|
6
|
+
RequestDataType["ChatUserInput"] = "chat-user-input";
|
|
7
|
+
RequestDataType["ClearChatHistory"] = "clear-chat-history";
|
|
8
|
+
RequestDataType["RunUICommandResponse"] = "run-ui-command-response";
|
|
9
|
+
RequestDataType["GenerateCode"] = "generate-code";
|
|
10
|
+
RequestDataType["CancelChatRequest"] = "cancel-chat-request";
|
|
11
|
+
RequestDataType["InlineCompletionRequest"] = "inline-completion-request";
|
|
12
|
+
RequestDataType["CancelInlineCompletionRequest"] = "cancel-inline-completion-request";
|
|
13
|
+
})(RequestDataType || (RequestDataType = {}));
|
|
14
|
+
export var BackendMessageType;
|
|
15
|
+
(function (BackendMessageType) {
|
|
16
|
+
BackendMessageType["StreamMessage"] = "stream-message";
|
|
17
|
+
BackendMessageType["StreamEnd"] = "stream-end";
|
|
18
|
+
BackendMessageType["RunUICommand"] = "run-ui-command";
|
|
19
|
+
BackendMessageType["GitHubCopilotLoginStatusChange"] = "github-copilot-login-status-change";
|
|
20
|
+
BackendMessageType["MCPServerStatusChange"] = "mcp-server-status-change";
|
|
21
|
+
BackendMessageType["ClaudeCodeStatusChange"] = "claude-code-status-change";
|
|
22
|
+
BackendMessageType["ClaudeCodeHeartbeat"] = "claude-code-heartbeat";
|
|
23
|
+
BackendMessageType["SkillsReloaded"] = "skills-reloaded";
|
|
24
|
+
})(BackendMessageType || (BackendMessageType = {}));
|
|
25
|
+
export var ResponseStreamDataType;
|
|
26
|
+
(function (ResponseStreamDataType) {
|
|
27
|
+
ResponseStreamDataType["LLMRaw"] = "llm-raw";
|
|
28
|
+
ResponseStreamDataType["Markdown"] = "markdown";
|
|
29
|
+
ResponseStreamDataType["MarkdownPart"] = "markdown-part";
|
|
30
|
+
ResponseStreamDataType["Image"] = "image";
|
|
31
|
+
ResponseStreamDataType["HTMLFrame"] = "html-frame";
|
|
32
|
+
ResponseStreamDataType["Button"] = "button";
|
|
33
|
+
ResponseStreamDataType["Anchor"] = "anchor";
|
|
34
|
+
ResponseStreamDataType["Progress"] = "progress";
|
|
35
|
+
ResponseStreamDataType["Confirmation"] = "confirmation";
|
|
36
|
+
ResponseStreamDataType["AskUserQuestion"] = "ask-user-question";
|
|
37
|
+
})(ResponseStreamDataType || (ResponseStreamDataType = {}));
|
|
38
|
+
export var ContextType;
|
|
39
|
+
(function (ContextType) {
|
|
40
|
+
ContextType["Custom"] = "custom";
|
|
41
|
+
ContextType["CurrentFile"] = "current-file";
|
|
42
|
+
ContextType["OutputContext"] = "output-context";
|
|
43
|
+
})(ContextType || (ContextType = {}));
|
|
44
|
+
export var MCPServerStatus;
|
|
45
|
+
(function (MCPServerStatus) {
|
|
46
|
+
MCPServerStatus["NotConnected"] = "not-connected";
|
|
47
|
+
MCPServerStatus["Connecting"] = "connecting";
|
|
48
|
+
MCPServerStatus["Disconnecting"] = "disconnecting";
|
|
49
|
+
MCPServerStatus["FailedToConnect"] = "failed-to-connect";
|
|
50
|
+
MCPServerStatus["Connected"] = "connected";
|
|
51
|
+
MCPServerStatus["UpdatingToolList"] = "updating-tool-list";
|
|
52
|
+
MCPServerStatus["UpdatedToolList"] = "updated-tool-list";
|
|
53
|
+
MCPServerStatus["UpdatingPromptList"] = "updating-prompt-list";
|
|
54
|
+
MCPServerStatus["UpdatedPromptList"] = "updated-prompt-list";
|
|
55
|
+
})(MCPServerStatus || (MCPServerStatus = {}));
|
|
56
|
+
export var BuiltinToolsetType;
|
|
57
|
+
(function (BuiltinToolsetType) {
|
|
58
|
+
BuiltinToolsetType["NotebookEdit"] = "nbi-notebook-edit";
|
|
59
|
+
BuiltinToolsetType["NotebookExecute"] = "nbi-notebook-execute";
|
|
60
|
+
BuiltinToolsetType["PythonFileEdit"] = "nbi-python-file-edit";
|
|
61
|
+
BuiltinToolsetType["FileEdit"] = "nbi-file-edit";
|
|
62
|
+
BuiltinToolsetType["FileRead"] = "nbi-file-read";
|
|
63
|
+
BuiltinToolsetType["CommandExecute"] = "nbi-command-execute";
|
|
64
|
+
})(BuiltinToolsetType || (BuiltinToolsetType = {}));
|
|
65
|
+
export const GITHUB_COPILOT_PROVIDER_ID = 'github-copilot';
|
|
66
|
+
export const CLAUDE_CODE_CHAT_PARTICIPANT_ID = 'claude-code';
|
|
67
|
+
export var AssistantMode;
|
|
68
|
+
(function (AssistantMode) {
|
|
69
|
+
AssistantMode["Default"] = "default";
|
|
70
|
+
AssistantMode["Claude"] = "claude";
|
|
71
|
+
})(AssistantMode || (AssistantMode = {}));
|
|
72
|
+
export var TelemetryEventType;
|
|
73
|
+
(function (TelemetryEventType) {
|
|
74
|
+
TelemetryEventType["InlineCompletionRequest"] = "inline-completion-request";
|
|
75
|
+
TelemetryEventType["ExplainThisRequest"] = "explain-this-request";
|
|
76
|
+
TelemetryEventType["FixThisCodeRequest"] = "fix-this-code-request";
|
|
77
|
+
TelemetryEventType["ExplainThisOutputRequest"] = "explain-this-output-request";
|
|
78
|
+
TelemetryEventType["TroubleshootThisOutputRequest"] = "troubleshoot-this-output-request";
|
|
79
|
+
TelemetryEventType["OutputFollowUpRequest"] = "output-follow-up-request";
|
|
80
|
+
TelemetryEventType["GenerateCodeRequest"] = "generate-code-request";
|
|
81
|
+
TelemetryEventType["ChatRequest"] = "chat-request";
|
|
82
|
+
TelemetryEventType["InlineChatRequest"] = "inline-chat-request";
|
|
83
|
+
TelemetryEventType["ChatResponse"] = "chat-response";
|
|
84
|
+
TelemetryEventType["InlineChatResponse"] = "inline-chat-response";
|
|
85
|
+
TelemetryEventType["InlineCompletionResponse"] = "inline-completion-response";
|
|
86
|
+
TelemetryEventType["Feedback"] = "feedback";
|
|
87
|
+
})(TelemetryEventType || (TelemetryEventType = {}));
|
|
88
|
+
export const INotebookIntelligence = new Token('@plmbr/notebook-intelligence:INotebookIntelligence', 'AI coding assistant for JupyterLab.');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor-id constants shared between the tour step definitions and the
|
|
3
|
+
* chat-sidebar JSX. Centralising these keeps the two halves coupled at
|
|
4
|
+
* the TypeScript level rather than by string identity — a typo on
|
|
5
|
+
* either side now surfaces at compile time instead of silently
|
|
6
|
+
* skipping a step at runtime.
|
|
7
|
+
*/
|
|
8
|
+
export declare const TOUR_ANCHOR: {
|
|
9
|
+
readonly newChat: "new-chat";
|
|
10
|
+
readonly settingsGear: "settings-gear";
|
|
11
|
+
readonly claudeHistory: "claude-history";
|
|
12
|
+
readonly slashCommands: "slash-commands";
|
|
13
|
+
readonly addContext: "add-context";
|
|
14
|
+
readonly uploadFile: "upload-file";
|
|
15
|
+
readonly promptInput: "prompt-input";
|
|
16
|
+
readonly chatMode: "chat-mode";
|
|
17
|
+
};
|
|
18
|
+
export type TourAnchorId = (typeof TOUR_ANCHOR)[keyof typeof TOUR_ANCHOR];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
|
|
2
|
+
/**
|
|
3
|
+
* Anchor-id constants shared between the tour step definitions and the
|
|
4
|
+
* chat-sidebar JSX. Centralising these keeps the two halves coupled at
|
|
5
|
+
* the TypeScript level rather than by string identity — a typo on
|
|
6
|
+
* either side now surfaces at compile time instead of silently
|
|
7
|
+
* skipping a step at runtime.
|
|
8
|
+
*/
|
|
9
|
+
export const TOUR_ANCHOR = {
|
|
10
|
+
newChat: 'new-chat',
|
|
11
|
+
settingsGear: 'settings-gear',
|
|
12
|
+
claudeHistory: 'claude-history',
|
|
13
|
+
slashCommands: 'slash-commands',
|
|
14
|
+
addContext: 'add-context',
|
|
15
|
+
uploadFile: 'upload-file',
|
|
16
|
+
promptInput: 'prompt-input',
|
|
17
|
+
chatMode: 'chat-mode'
|
|
18
|
+
};
|