xtralab 0.15.0 → 0.15.2
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/README.md +65 -30
- package/lib/about/icons.d.ts +0 -5
- package/lib/about/icons.js +0 -5
- package/lib/about/index.d.ts +4 -8
- package/lib/about/index.js +6 -17
- package/lib/agentSessions.d.ts +9 -29
- package/lib/agentSessions.js +2 -7
- package/lib/askAgent/editorSelection.d.ts +20 -26
- package/lib/askAgent/editorSelection.js +11 -26
- package/lib/askAgent/icons.d.ts +2 -3
- package/lib/askAgent/icons.js +2 -3
- package/lib/askAgent/index.d.ts +4 -26
- package/lib/askAgent/index.js +54 -158
- package/lib/askAgent/popup.d.ts +12 -16
- package/lib/askAgent/popup.js +18 -37
- package/lib/askAgent/prompt.d.ts +3 -5
- package/lib/askAgent/prompt.js +6 -19
- package/lib/askAgent/queue.d.ts +11 -21
- package/lib/askAgent/queue.js +9 -19
- package/lib/askAgent/queuePanel.d.ts +13 -18
- package/lib/askAgent/queuePanel.js +15 -37
- package/lib/askAgent/targetPicker.d.ts +2 -9
- package/lib/askAgent/targetPicker.js +6 -11
- package/lib/askAgent/tokens.d.ts +32 -46
- package/lib/askAgent/tokens.js +4 -6
- package/lib/commandBar/index.d.ts +4 -13
- package/lib/commandBar/index.js +21 -39
- package/lib/customPanel/index.js +15 -0
- package/lib/editorBreadcrumbs/index.d.ts +3 -6
- package/lib/editorBreadcrumbs/index.js +10 -6
- package/lib/editorBreadcrumbs/widget.d.ts +17 -4
- package/lib/editorBreadcrumbs/widget.js +11 -17
- package/lib/editorIndent/index.d.ts +4 -12
- package/lib/editorIndent/index.js +8 -23
- package/lib/fileBrowser/commands.d.ts +29 -19
- package/lib/fileBrowser/commands.js +83 -97
- package/lib/fileBrowser/contents.d.ts +3 -0
- package/lib/fileBrowser/dragAndDrop.d.ts +17 -4
- package/lib/fileBrowser/dragAndDrop.js +2 -7
- package/lib/fileBrowser/fileBrowser.d.ts +19 -9
- package/lib/fileBrowser/fileBrowser.js +70 -222
- package/lib/fileBrowser/gitStatus.d.ts +16 -10
- package/lib/fileBrowser/gitStatus.js +31 -30
- package/lib/fileBrowser/gitignore.d.ts +4 -17
- package/lib/fileBrowser/gitignore.js +4 -25
- package/lib/fileBrowser/icons.d.ts +7 -17
- package/lib/fileBrowser/icons.js +25 -80
- package/lib/fileBrowser/index.js +2 -4
- package/lib/fileBrowser/widget.d.ts +141 -48
- package/lib/fileBrowser/widget.js +102 -4
- package/lib/fileTypeIcons/index.js +0 -10
- package/lib/git/api.d.ts +5 -13
- package/lib/git/api.js +10 -36
- package/lib/git/askRequest.d.ts +4 -8
- package/lib/git/askRequest.js +6 -20
- package/lib/git/commands.d.ts +45 -5
- package/lib/git/commands.js +20 -13
- package/lib/git/diffModel.js +4 -0
- package/lib/git/diffPreferences.d.ts +90 -0
- package/lib/git/diffPreferences.js +107 -0
- package/lib/git/diffProvider.js +10 -2
- package/lib/git/diffSurface.d.ts +64 -63
- package/lib/git/diffSurface.js +72 -213
- package/lib/git/diffTheme.d.ts +7 -0
- package/lib/git/diffTheme.js +23 -0
- package/lib/git/diffWidget.d.ts +70 -14
- package/lib/git/diffWidget.js +100 -94
- package/lib/git/imageDiff.d.ts +14 -6
- package/lib/git/imageDiff.js +19 -75
- package/lib/git/index.d.ts +0 -3
- package/lib/git/index.js +44 -10
- package/lib/git/notebookDiff.d.ts +110 -33
- package/lib/git/notebookDiff.js +55 -197
- package/lib/git/tokens.d.ts +73 -31
- package/lib/git/tokens.js +2 -3
- package/lib/highlight/index.d.ts +4 -10
- package/lib/highlight/index.js +10 -41
- package/lib/index.d.ts +0 -9
- package/lib/index.js +0 -9
- package/lib/launcher/agents.d.ts +55 -51
- package/lib/launcher/agents.js +15 -57
- package/lib/launcher/availability.d.ts +3 -9
- package/lib/launcher/availability.js +3 -9
- package/lib/launcher/commands.d.ts +7 -32
- package/lib/launcher/commands.js +14 -45
- package/lib/launcher/dashboard.d.ts +19 -24
- package/lib/launcher/dashboard.js +21 -67
- package/lib/launcher/editorRegistry.d.ts +10 -22
- package/lib/launcher/editorRegistry.js +14 -18
- package/lib/launcher/editors.d.ts +39 -45
- package/lib/launcher/editors.js +8 -34
- package/lib/launcher/icons.d.ts +0 -12
- package/lib/launcher/icons.js +5 -39
- package/lib/launcher/index.js +12 -55
- package/lib/launcher/invocation.d.ts +4 -10
- package/lib/launcher/invocation.js +7 -22
- package/lib/launcher/registry.d.ts +9 -7
- package/lib/launcher/registry.js +9 -7
- package/lib/launcher/tokens.d.ts +10 -22
- package/lib/launcher/tokens.js +5 -8
- package/lib/menuBar/index.d.ts +3 -10
- package/lib/menuBar/index.js +11 -28
- package/lib/menus/index.d.ts +3 -9
- package/lib/menus/index.js +14 -30
- package/lib/omnibox/files.d.ts +2 -4
- package/lib/omnibox/files.js +5 -11
- package/lib/omnibox/index.d.ts +4 -14
- package/lib/omnibox/index.js +9 -27
- package/lib/omnibox/model.d.ts +38 -10
- package/lib/omnibox/model.js +15 -33
- package/lib/omnibox/recents.d.ts +15 -17
- package/lib/omnibox/recents.js +12 -17
- package/lib/omnibox/tokens.d.ts +5 -10
- package/lib/omnibox/tokens.js +2 -6
- package/lib/omnibox/widget.d.ts +11 -7
- package/lib/omnibox/widget.js +8 -16
- package/lib/searchReplace/index.d.ts +4 -20
- package/lib/searchReplace/index.js +7 -27
- package/lib/showOutput/index.d.ts +3 -12
- package/lib/showOutput/index.js +6 -22
- package/lib/sidebar/index.d.ts +4 -7
- package/lib/sidebar/index.js +5 -12
- package/lib/terminalNotifications/index.d.ts +4 -10
- package/lib/terminalNotifications/index.js +6 -20
- package/lib/terminals/agentTerminals.d.ts +12 -5
- package/lib/terminals/agentTerminals.js +25 -44
- package/lib/terminals/detection.d.ts +4 -8
- package/lib/terminals/detection.js +4 -8
- package/lib/terminals/index.d.ts +0 -35
- package/lib/terminals/index.js +12 -101
- package/lib/terminals/model.d.ts +64 -139
- package/lib/terminals/model.js +80 -220
- package/lib/terminals/tokens.d.ts +11 -22
- package/lib/terminals/tokens.js +2 -2
- package/lib/terminals/widget.d.ts +43 -13
- package/lib/terminals/widget.js +33 -18
- package/lib/topBar/icons.d.ts +3 -8
- package/lib/topBar/icons.js +3 -8
- package/lib/topBar/index.d.ts +4 -11
- package/lib/topBar/index.js +10 -38
- package/lib/walkthrough/index.d.ts +4 -9
- package/lib/walkthrough/index.js +6 -20
- package/lib/walkthrough/panel.d.ts +40 -9
- package/lib/walkthrough/panel.js +4 -10
- package/package.json +5 -3
- package/schema/git-diff-preferences.json +42 -0
- package/src/about/icons.ts +0 -5
- package/src/about/index.tsx +6 -17
- package/src/agentSessions.ts +9 -29
- package/src/askAgent/editorSelection.ts +22 -29
- package/src/askAgent/icons.ts +2 -3
- package/src/askAgent/index.ts +54 -158
- package/src/askAgent/popup.tsx +23 -45
- package/src/askAgent/prompt.ts +6 -19
- package/src/askAgent/queue.ts +13 -24
- package/src/askAgent/queuePanel.tsx +21 -46
- package/src/askAgent/targetPicker.tsx +5 -15
- package/src/askAgent/tokens.ts +32 -46
- package/src/commandBar/index.ts +24 -39
- package/src/customPanel/index.ts +15 -0
- package/src/editorBreadcrumbs/index.ts +10 -6
- package/src/editorBreadcrumbs/widget.ts +23 -17
- package/src/editorIndent/index.ts +17 -23
- package/src/fileBrowser/commands.ts +119 -96
- package/src/fileBrowser/contents.ts +3 -0
- package/src/fileBrowser/dragAndDrop.ts +17 -7
- package/src/fileBrowser/fileBrowser.tsx +86 -230
- package/src/fileBrowser/gitStatus.ts +36 -33
- package/src/fileBrowser/gitignore.ts +4 -25
- package/src/fileBrowser/icons.ts +25 -80
- package/src/fileBrowser/index.ts +2 -4
- package/src/fileBrowser/widget.tsx +171 -50
- package/src/fileTypeIcons/index.ts +0 -10
- package/src/git/api.ts +10 -36
- package/src/git/askRequest.ts +6 -20
- package/src/git/commands.ts +83 -11
- package/src/git/diffModel.ts +25 -0
- package/src/git/diffPreferences.ts +192 -0
- package/src/git/diffProvider.tsx +11 -2
- package/src/git/diffSurface.tsx +165 -286
- package/src/git/diffTheme.ts +24 -0
- package/src/git/diffWidget.tsx +194 -134
- package/src/git/imageDiff.tsx +56 -84
- package/src/git/index.ts +54 -10
- package/src/git/notebookDiff.tsx +214 -240
- package/src/git/tokens.ts +73 -31
- package/src/highlight/index.ts +10 -41
- package/src/index.ts +0 -9
- package/src/launcher/agents.ts +64 -95
- package/src/launcher/availability.ts +3 -9
- package/src/launcher/commands.ts +14 -51
- package/src/launcher/dashboard.tsx +49 -88
- package/src/launcher/editorRegistry.ts +21 -29
- package/src/launcher/editors.ts +39 -58
- package/src/launcher/icons.ts +5 -39
- package/src/launcher/index.ts +12 -55
- package/src/launcher/invocation.ts +7 -22
- package/src/launcher/registry.ts +9 -7
- package/src/launcher/tokens.ts +10 -22
- package/src/menuBar/index.ts +11 -28
- package/src/menus/index.ts +14 -30
- package/src/omnibox/files.ts +10 -14
- package/src/omnibox/index.ts +9 -27
- package/src/omnibox/model.ts +50 -38
- package/src/omnibox/recents.ts +17 -22
- package/src/omnibox/tokens.ts +5 -10
- package/src/omnibox/widget.tsx +14 -19
- package/src/searchReplace/index.ts +7 -27
- package/src/showOutput/index.ts +6 -22
- package/src/sidebar/index.ts +20 -12
- package/src/terminalNotifications/index.ts +42 -25
- package/src/terminals/agentTerminals.ts +25 -49
- package/src/terminals/detection.ts +4 -8
- package/src/terminals/index.ts +12 -101
- package/src/terminals/model.ts +130 -246
- package/src/terminals/tokens.ts +11 -22
- package/src/terminals/widget.tsx +48 -31
- package/src/topBar/icons.ts +3 -8
- package/src/topBar/index.ts +21 -44
- package/src/walkthrough/index.ts +6 -20
- package/src/walkthrough/panel.ts +40 -10
- package/style/about.css +2 -7
- package/style/askAgent.css +8 -40
- package/style/base.css +9 -45
- package/style/chrome.css +108 -308
- package/style/commandBar.css +4 -20
- package/style/customPanel.css +1 -4
- package/style/git.css +26 -186
- package/style/highlight.css +1 -3
- package/style/launcher.css +6 -70
- package/style/omnibox.css +2 -14
- package/style/showOutput.css +0 -6
- package/style/sidebar.css +29 -9
- package/style/tabs.css +5 -13
- package/style/terminals.css +6 -53
- package/style/topBar.css +2 -22
- package/style/walkthrough.css +0 -8
package/src/askAgent/prompt.ts
CHANGED
|
@@ -14,10 +14,8 @@ export function serverPath(context: IAskAgentContext): string {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Cap on the
|
|
18
|
-
*
|
|
19
|
-
* themselves — so a very long selection is trimmed instead of being typed
|
|
20
|
-
* into the terminal wholesale.
|
|
17
|
+
* Cap on the embedded snippet; the path and line range are the
|
|
18
|
+
* authoritative pointers, so a very long selection is trimmed.
|
|
21
19
|
*/
|
|
22
20
|
const MAX_SNIPPET_CHARS = 2000;
|
|
23
21
|
|
|
@@ -33,10 +31,6 @@ function fenceFor(text: string): string {
|
|
|
33
31
|
return '`'.repeat(Math.max(3, longest + 1));
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
/**
|
|
37
|
-
* Trim `text` to {@link MAX_SNIPPET_CHARS}, cutting at a line boundary.
|
|
38
|
-
* Returns the (possibly shortened) snippet and whether anything was dropped.
|
|
39
|
-
*/
|
|
40
34
|
function clampSnippet(text: string): { snippet: string; truncated: boolean } {
|
|
41
35
|
if (text.length <= MAX_SNIPPET_CHARS) {
|
|
42
36
|
return { snippet: text, truncated: false };
|
|
@@ -58,7 +52,7 @@ function locatorFor(context: IAskAgentContext): string {
|
|
|
58
52
|
const where: string[] = [`\`${context.path}\``];
|
|
59
53
|
if (context.cell !== undefined) {
|
|
60
54
|
// Both orderings so the agent can count cells or index the nbformat
|
|
61
|
-
// `cells` array
|
|
55
|
+
// `cells` array.
|
|
62
56
|
where.push(
|
|
63
57
|
`${context.cell.type} cell ${context.cell.index + 1} ` +
|
|
64
58
|
`(0-based index ${context.cell.index})`
|
|
@@ -78,11 +72,6 @@ function locatorFor(context: IAskAgentContext): string {
|
|
|
78
72
|
return where.join(', ');
|
|
79
73
|
}
|
|
80
74
|
|
|
81
|
-
/**
|
|
82
|
-
* The blocks describing one comment: `headline`, the selected snippet in a
|
|
83
|
-
* code fence (when there is one), then the user's instruction. Blocks are
|
|
84
|
-
* joined with blank lines by the callers.
|
|
85
|
-
*/
|
|
86
75
|
function commentParts(
|
|
87
76
|
context: IAskAgentContext,
|
|
88
77
|
instruction: string,
|
|
@@ -102,11 +91,9 @@ function commentParts(
|
|
|
102
91
|
}
|
|
103
92
|
|
|
104
93
|
/**
|
|
105
|
-
* Compose the prompt handed to the agent CLI:
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* The scaffold is written in English on purpose — it is consumed by the
|
|
109
|
-
* agent, not shown in the UI, and the agent CLIs are English-first.
|
|
94
|
+
* Compose the prompt handed to the agent CLI: locator, fenced snippet,
|
|
95
|
+
* instruction. The scaffold is English on purpose — consumed by the agent,
|
|
96
|
+
* not shown in the UI.
|
|
110
97
|
*/
|
|
111
98
|
export function buildPrompt(
|
|
112
99
|
context: IAskAgentContext,
|
package/src/askAgent/queue.ts
CHANGED
|
@@ -5,8 +5,8 @@ import type { AskAgentTarget, IAskAgentContext } from './tokens';
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* One queued prompt: a code selection, the user's instruction about it, and
|
|
8
|
-
* where it should go. Every prompt is independent — a queue
|
|
9
|
-
*
|
|
8
|
+
* where it should go. Every prompt is independent — a queue mixes targets
|
|
9
|
+
* freely.
|
|
10
10
|
*/
|
|
11
11
|
export interface IQueuedPrompt {
|
|
12
12
|
/**
|
|
@@ -25,9 +25,8 @@ export interface IQueuedPrompt {
|
|
|
25
25
|
instruction: string;
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* The destination picked
|
|
29
|
-
*
|
|
30
|
-
* longer parses — the panel then asks for a new pick before sending.
|
|
28
|
+
* The destination picked in the popup, editable in the panel. `null` when
|
|
29
|
+
* a persisted target no longer parses — the panel then asks for a new pick.
|
|
31
30
|
*/
|
|
32
31
|
target: AskAgentTarget | null;
|
|
33
32
|
}
|
|
@@ -39,15 +38,9 @@ function nextId(): string {
|
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
/**
|
|
42
|
-
* The accumulated ask-agent prompts awaiting a batch send.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* the popup appends entries here instead of sending, the side panel lists
|
|
46
|
-
* and edits them, and one batch send flushes the lot, delivering each
|
|
47
|
-
* destination's prompts as one numbered message. The queue itself is a
|
|
48
|
-
* plain in-memory model; the plugin mirrors it into the JupyterLab state
|
|
49
|
-
* database (via {@link serializeQueuedPrompts}) so a page reload does not
|
|
50
|
-
* silently drop typed comments.
|
|
41
|
+
* The accumulated ask-agent prompts awaiting a batch send. A plain
|
|
42
|
+
* in-memory model; the plugin mirrors it into the state database so a page
|
|
43
|
+
* reload does not silently drop typed comments.
|
|
51
44
|
*/
|
|
52
45
|
export class PromptQueue {
|
|
53
46
|
constructor(items: IQueuedPrompt[] = []) {
|
|
@@ -125,8 +118,7 @@ export class PromptQueue {
|
|
|
125
118
|
}
|
|
126
119
|
|
|
127
120
|
/**
|
|
128
|
-
* Remove several queued prompts at once (one signal emission)
|
|
129
|
-
* a batch send succeeds for one target while other targets' prompts stay.
|
|
121
|
+
* Remove several queued prompts at once (one signal emission).
|
|
130
122
|
*/
|
|
131
123
|
removeMany(ids: readonly string[]): void {
|
|
132
124
|
const drop = new Set(ids);
|
|
@@ -160,9 +152,8 @@ export class PromptQueue {
|
|
|
160
152
|
}
|
|
161
153
|
|
|
162
154
|
/**
|
|
163
|
-
* Validate one persisted context
|
|
164
|
-
*
|
|
165
|
-
* state-database edits) degrades an entry instead of poisoning the queue.
|
|
155
|
+
* Validate one persisted context; schema drift degrades an entry instead
|
|
156
|
+
* of poisoning the queue.
|
|
166
157
|
*/
|
|
167
158
|
function sanitizeContext(value: unknown): IAskAgentContext | null {
|
|
168
159
|
if (value === null || typeof value !== 'object') {
|
|
@@ -225,9 +216,8 @@ function sanitizeTarget(value: unknown): AskAgentTarget | null {
|
|
|
225
216
|
}
|
|
226
217
|
|
|
227
218
|
/**
|
|
228
|
-
* Rebuild queued prompts from
|
|
229
|
-
*
|
|
230
|
-
* convenience buffer, not a document.
|
|
219
|
+
* Rebuild queued prompts from the state database; entries that no longer
|
|
220
|
+
* parse are dropped silently.
|
|
231
221
|
*/
|
|
232
222
|
export function deserializeQueuedPrompts(value: unknown): IQueuedPrompt[] {
|
|
233
223
|
if (!Array.isArray(value)) {
|
|
@@ -255,8 +245,7 @@ export function deserializeQueuedPrompts(value: unknown): IQueuedPrompt[] {
|
|
|
255
245
|
|
|
256
246
|
/**
|
|
257
247
|
* The queue as a JSON value for the state database. Ids are session-scoped
|
|
258
|
-
*
|
|
259
|
-
* assigns fresh ones on load.
|
|
248
|
+
* and not persisted; fresh ones are assigned on load.
|
|
260
249
|
*/
|
|
261
250
|
export function serializeQueuedPrompts(
|
|
262
251
|
items: readonly IQueuedPrompt[]
|
|
@@ -19,25 +19,16 @@ import type { IQueuedPrompt, PromptQueue } from './queue';
|
|
|
19
19
|
import type { ISessionTarget } from './targetPicker';
|
|
20
20
|
import type { AskAgentTarget } from './tokens';
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Command the context buttons dispatch; keeps the panel decoupled from the plugin.
|
|
24
|
-
*/
|
|
25
22
|
const HIGHLIGHT_LINES_COMMAND = 'xtralab:highlight-lines';
|
|
26
23
|
|
|
27
24
|
/**
|
|
28
|
-
* Textarea height that fits `text` without scrolling,
|
|
29
|
-
*
|
|
30
|
-
* crowd out the rest of the queue.
|
|
25
|
+
* Textarea height that fits `text` without scrolling, bounded so one long
|
|
26
|
+
* comment cannot crowd out the rest of the queue.
|
|
31
27
|
*/
|
|
32
28
|
function rowsFor(text: string): number {
|
|
33
29
|
return Math.min(8, Math.max(2, text.split('\n').length));
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
/**
|
|
37
|
-
* A target as a `<select>` option value: `session:<name>` for a running
|
|
38
|
-
* agent terminal, `new:<agentId>` for a fresh terminal, `''` for a missing
|
|
39
|
-
* target (the placeholder option).
|
|
40
|
-
*/
|
|
41
32
|
function encodeTarget(target: AskAgentTarget | null): string {
|
|
42
33
|
if (target === null) {
|
|
43
34
|
return '';
|
|
@@ -57,10 +48,6 @@ function decodeTarget(value: string): AskAgentTarget | null {
|
|
|
57
48
|
return null;
|
|
58
49
|
}
|
|
59
50
|
|
|
60
|
-
/**
|
|
61
|
-
* Whether `target` can be sent to right now: its session is still running,
|
|
62
|
-
* or its agent still accepts a command-line prompt.
|
|
63
|
-
*/
|
|
64
51
|
function targetIsLive(
|
|
65
52
|
target: AskAgentTarget | null,
|
|
66
53
|
agents: readonly IAgent[],
|
|
@@ -86,8 +73,8 @@ function QueuePanelComponent(props: AskAgentQueuePanel.IOptions): JSX.Element {
|
|
|
86
73
|
onClear
|
|
87
74
|
} = props;
|
|
88
75
|
|
|
89
|
-
//
|
|
90
|
-
//
|
|
76
|
+
// The widget re-renders on every queue, agent registry and terminal
|
|
77
|
+
// change, so these snapshots stay current.
|
|
91
78
|
const items = queue.items;
|
|
92
79
|
const agents = readAgents();
|
|
93
80
|
const targets = readTargets();
|
|
@@ -102,10 +89,8 @@ function QueuePanelComponent(props: AskAgentQueuePanel.IOptions): JSX.Element {
|
|
|
102
89
|
const jumpTo = (item: IQueuedPrompt): void => {
|
|
103
90
|
const { context } = item;
|
|
104
91
|
const path = serverPath(context);
|
|
105
|
-
// The highlighter needs line numbers
|
|
106
|
-
//
|
|
107
|
-
// selections may come from another revision — just open the document
|
|
108
|
-
// in those cases.
|
|
92
|
+
// The highlighter needs working-file line numbers: notebook lines are
|
|
93
|
+
// cell-relative and diff lines may index another revision — just open.
|
|
109
94
|
const jump =
|
|
110
95
|
context.cell === undefined &&
|
|
111
96
|
context.startLine !== undefined &&
|
|
@@ -145,9 +130,6 @@ function QueuePanelComponent(props: AskAgentQueuePanel.IOptions): JSX.Element {
|
|
|
145
130
|
const missing = item.instruction.trim().length === 0;
|
|
146
131
|
const target = item.target;
|
|
147
132
|
const live = targetIsLive(target, agents, targets);
|
|
148
|
-
// Say what sending will do for this prompt — paste into a running
|
|
149
|
-
// terminal, or start a fresh one — and badge it with the agent's
|
|
150
|
-
// icon, so a mixed queue can be scanned without opening dropdowns.
|
|
151
133
|
let icon: LabIcon | null = null;
|
|
152
134
|
let targetTitle = trans.__(
|
|
153
135
|
'The destination picked for this prompt is gone — choose another'
|
|
@@ -202,10 +184,8 @@ function QueuePanelComponent(props: AskAgentQueuePanel.IOptions): JSX.Element {
|
|
|
202
184
|
{item.context.text}
|
|
203
185
|
</pre>
|
|
204
186
|
)}
|
|
205
|
-
{/* Uncontrolled on purpose:
|
|
206
|
-
|
|
207
|
-
late reverts keystrokes and jumps the caret. The `key` on
|
|
208
|
-
the surrounding <li> still remounts it per queue entry. */}
|
|
187
|
+
{/* Uncontrolled on purpose: re-renders arrive as posted Lumino
|
|
188
|
+
updates, late enough to revert keystrokes if controlled. */}
|
|
209
189
|
<textarea
|
|
210
190
|
className="jp-xtralab-AskAgentQueue-instruction"
|
|
211
191
|
rows={rowsFor(item.instruction)}
|
|
@@ -324,15 +304,10 @@ function QueuePanelComponent(props: AskAgentQueuePanel.IOptions): JSX.Element {
|
|
|
324
304
|
}
|
|
325
305
|
|
|
326
306
|
/**
|
|
327
|
-
* The right-sidebar review panel for queued ask-agent prompts
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
* send button that flushes the whole queue in one go: prompts sharing a
|
|
332
|
-
* destination are combined into one numbered message, and each destination
|
|
333
|
-
* gets its own delivery. The widget re-renders on queue changes itself; the
|
|
334
|
-
* plugin additionally ties it to the agent registry and terminal signals so
|
|
335
|
-
* the destination choices stay current.
|
|
307
|
+
* The right-sidebar review panel for queued ask-agent prompts: an editable
|
|
308
|
+
* list with per-prompt destinations, plus a send button that flushes the
|
|
309
|
+
* whole queue, combining prompts that share a destination into one
|
|
310
|
+
* numbered message.
|
|
336
311
|
*/
|
|
337
312
|
export class AskAgentQueuePanel extends ReactWidget {
|
|
338
313
|
constructor(options: AskAgentQueuePanel.IOptions) {
|
|
@@ -342,15 +317,16 @@ export class AskAgentQueuePanel extends ReactWidget {
|
|
|
342
317
|
options.queue.changed.connect(this._onQueueChanged, this);
|
|
343
318
|
}
|
|
344
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Render the panel content.
|
|
322
|
+
*/
|
|
345
323
|
render(): JSX.Element {
|
|
346
324
|
return <QueuePanelComponent {...this._options} />;
|
|
347
325
|
}
|
|
348
326
|
|
|
349
327
|
/**
|
|
350
|
-
* Dispose on close
|
|
351
|
-
*
|
|
352
|
-
* behind. The plugin recreates the panel in the side area on demand; the
|
|
353
|
-
* queue itself lives on in the model.
|
|
328
|
+
* Dispose on close rather than leaving a detached widget behind; the
|
|
329
|
+
* plugin recreates the panel on demand and the queue lives on in the model.
|
|
354
330
|
*/
|
|
355
331
|
protected onCloseRequest(msg: Message): void {
|
|
356
332
|
super.onCloseRequest(msg);
|
|
@@ -393,9 +369,8 @@ export namespace AskAgentQueuePanel {
|
|
|
393
369
|
targets: () => ISessionTarget[];
|
|
394
370
|
|
|
395
371
|
/**
|
|
396
|
-
* Live reader of whether a batch send is in flight
|
|
397
|
-
*
|
|
398
|
-
* flush cannot be double-delivered.
|
|
372
|
+
* Live reader of whether a batch send is in flight; while true the send
|
|
373
|
+
* and clear buttons are disabled.
|
|
399
374
|
*/
|
|
400
375
|
sending: () => boolean;
|
|
401
376
|
|
|
@@ -405,8 +380,8 @@ export namespace AskAgentQueuePanel {
|
|
|
405
380
|
trans: TranslationBundle;
|
|
406
381
|
|
|
407
382
|
/**
|
|
408
|
-
* Send every queued prompt to its own destination (
|
|
409
|
-
*
|
|
383
|
+
* Send every queued prompt to its own destination (called only while
|
|
384
|
+
* all instructions and destinations are valid).
|
|
410
385
|
*/
|
|
411
386
|
onSend: () => void;
|
|
412
387
|
|
|
@@ -32,11 +32,9 @@ export interface ISessionTarget {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* Keyboard support
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* radio, wrapping around. Selection follows focus, so the handler clicks
|
|
39
|
-
* the neighbour and the re-render moves the roving tabindex along.
|
|
35
|
+
* Keyboard support for the radiogroups, per the ARIA radio pattern: one tab
|
|
36
|
+
* stop, arrow keys move and select — the handler clicks the neighbour and
|
|
37
|
+
* the re-render moves the roving tabindex along.
|
|
40
38
|
*/
|
|
41
39
|
function onRadioGroupKeyDown(event: React.KeyboardEvent<HTMLElement>): void {
|
|
42
40
|
let delta: number;
|
|
@@ -67,18 +65,11 @@ function onRadioGroupKeyDown(event: React.KeyboardEvent<HTMLElement>): void {
|
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
67
|
* The chip row picking where a prompt goes: "New terminal" plus one chip
|
|
70
|
-
* per running agent session. Renders nothing while no
|
|
71
|
-
*
|
|
72
|
-
* be noise).
|
|
68
|
+
* per running agent session. Renders nothing while no session is running
|
|
69
|
+
* (a new terminal is then the only possibility).
|
|
73
70
|
*/
|
|
74
71
|
export function TargetChips(props: {
|
|
75
|
-
/**
|
|
76
|
-
* Agents that could start in a new terminal; gates the "New terminal" chip.
|
|
77
|
-
*/
|
|
78
72
|
agents: IAgent[];
|
|
79
|
-
/**
|
|
80
|
-
* The running agent sessions.
|
|
81
|
-
*/
|
|
82
73
|
targets: ISessionTarget[];
|
|
83
74
|
/**
|
|
84
75
|
* The selected session name, or `null` for a new terminal.
|
|
@@ -194,7 +185,6 @@ export function AgentChoices(props: {
|
|
|
194
185
|
'jp-xtralab-AskAgent-agentButton' +
|
|
195
186
|
(agent.id === agentId ? ' jp-mod-selected' : '')
|
|
196
187
|
}
|
|
197
|
-
// Keep focus where the user is typing while picking an agent.
|
|
198
188
|
onMouseDown={event => event.preventDefault()}
|
|
199
189
|
onClick={() => onSelect(agent.id)}
|
|
200
190
|
>
|
package/src/askAgent/tokens.ts
CHANGED
|
@@ -1,39 +1,34 @@
|
|
|
1
1
|
import { Token } from '@lumino/coreutils';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* other plugins can reference it without importing the plugin internals.
|
|
4
|
+
* Command id opening the ask-agent popup for the current editor selection;
|
|
5
|
+
* exposed so other plugins can reference it without the plugin internals.
|
|
7
6
|
*/
|
|
8
7
|
export const ASK_AGENT_COMMAND = 'xtralab:ask-agent';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
|
-
* A code location (and optionally the selected
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* selection, diff line selection — produces consistently worded prompts.
|
|
10
|
+
* A code location (and optionally the selected text) a prompt should point
|
|
11
|
+
* an agent at; the plugin composes the fields into consistently worded
|
|
12
|
+
* prompts for every entry point.
|
|
15
13
|
*/
|
|
16
14
|
export interface IAskAgentContext {
|
|
17
15
|
/**
|
|
18
|
-
* Path of the file
|
|
19
|
-
*
|
|
20
|
-
* it directly.
|
|
16
|
+
* Path of the file, relative to {@link cwd} (or to the server root when
|
|
17
|
+
* no cwd is given).
|
|
21
18
|
*/
|
|
22
19
|
path: string;
|
|
23
20
|
|
|
24
21
|
/**
|
|
25
|
-
* Server-relative directory the agent's terminal starts in.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* Server-relative directory the agent's terminal starts in. Diff
|
|
23
|
+
* selections pass the git repository root so the agent can run git
|
|
24
|
+
* commands right away.
|
|
28
25
|
*/
|
|
29
26
|
cwd?: string;
|
|
30
27
|
|
|
31
28
|
/**
|
|
32
|
-
* The notebook cell the selection lives in
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `raw`). When set, {@link startLine}/{@link endLine} count within the
|
|
36
|
-
* cell's source rather than within a file.
|
|
29
|
+
* The notebook cell the selection lives in. `index` is the 0-based
|
|
30
|
+
* nbformat position, `type` the nbformat cell type; when set,
|
|
31
|
+
* {@link startLine}/{@link endLine} count within the cell's source.
|
|
37
32
|
*/
|
|
38
33
|
cell?: {
|
|
39
34
|
index: number;
|
|
@@ -41,8 +36,8 @@ export interface IAskAgentContext {
|
|
|
41
36
|
};
|
|
42
37
|
|
|
43
38
|
/**
|
|
44
|
-
* First selected line, 1-indexed and inclusive. Omit when no line range
|
|
45
|
-
* known
|
|
39
|
+
* First selected line, 1-indexed and inclusive. Omit when no line range
|
|
40
|
+
* is known.
|
|
46
41
|
*/
|
|
47
42
|
startLine?: number;
|
|
48
43
|
|
|
@@ -53,40 +48,34 @@ export interface IAskAgentContext {
|
|
|
53
48
|
endLine?: number;
|
|
54
49
|
|
|
55
50
|
/**
|
|
56
|
-
* Whether
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* whose numbers must not be used to highlight the working file. Omitted
|
|
60
|
-
* means `true`.
|
|
51
|
+
* Whether the lines index the file's current working-tree content.
|
|
52
|
+
* `false` for diff selections taken from another revision, whose numbers
|
|
53
|
+
* must not highlight the working file. Omitted means `true`.
|
|
61
54
|
*/
|
|
62
55
|
linesInWorkingFile?: boolean;
|
|
63
56
|
|
|
64
57
|
/**
|
|
65
|
-
* The selected source text
|
|
66
|
-
* the prompt then relies on the path and line range alone.
|
|
58
|
+
* The selected source text; may be empty when only a location is known.
|
|
67
59
|
*/
|
|
68
60
|
text: string;
|
|
69
61
|
|
|
70
62
|
/**
|
|
71
|
-
* Extra agent-facing locator appended after the line range
|
|
72
|
-
*
|
|
73
|
-
* it is consumed by the agent, not shown in the UI.
|
|
63
|
+
* Extra agent-facing locator appended after the line range, e.g. `the old
|
|
64
|
+
* side (INDEX) of the git diff`. English — consumed by the agent, not the UI.
|
|
74
65
|
*/
|
|
75
66
|
location?: string;
|
|
76
67
|
|
|
77
68
|
/**
|
|
78
|
-
* Short user-facing tag shown in the popup header
|
|
79
|
-
*
|
|
80
|
-
* range reads naturally as the file's current content.
|
|
69
|
+
* Short user-facing tag shown in the popup header, e.g. "old version".
|
|
70
|
+
* Translated, unlike {@link location}.
|
|
81
71
|
*/
|
|
82
72
|
note?: string;
|
|
83
73
|
}
|
|
84
74
|
|
|
85
75
|
/**
|
|
86
76
|
* Where a submitted prompt goes: a fresh terminal started with the chosen
|
|
87
|
-
* agent's command, or an existing
|
|
88
|
-
*
|
|
89
|
-
* is busy).
|
|
77
|
+
* agent's command, or an existing session whose running agent receives the
|
|
78
|
+
* prompt in its input box (queued by the agent itself when busy).
|
|
90
79
|
*/
|
|
91
80
|
export type AskAgentTarget =
|
|
92
81
|
| { kind: 'new'; agentId: string }
|
|
@@ -103,18 +92,16 @@ export interface IAskAgentRequest {
|
|
|
103
92
|
context: IAskAgentContext;
|
|
104
93
|
|
|
105
94
|
/**
|
|
106
|
-
* Viewport rectangle the popup anchors to
|
|
107
|
-
*
|
|
108
|
-
* center of the viewport.
|
|
95
|
+
* Viewport rectangle the popup anchors to; `null` positions it near the
|
|
96
|
+
* top center of the viewport.
|
|
109
97
|
*/
|
|
110
98
|
anchor: DOMRect | null;
|
|
111
99
|
}
|
|
112
100
|
|
|
113
101
|
/**
|
|
114
|
-
* The ask-agent popup: a
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* running in an existing one.
|
|
102
|
+
* The ask-agent popup: a floating prompt box that sends the given code
|
|
103
|
+
* selection plus the user's instruction to a coding agent, in a fresh or
|
|
104
|
+
* running terminal.
|
|
118
105
|
*/
|
|
119
106
|
export interface IAskAgent {
|
|
120
107
|
/**
|
|
@@ -129,9 +116,8 @@ export interface IAskAgent {
|
|
|
129
116
|
}
|
|
130
117
|
|
|
131
118
|
/**
|
|
132
|
-
* DI token for {@link IAskAgent}
|
|
133
|
-
*
|
|
134
|
-
* by the git diff plugins to offer "ask an agent about these lines".
|
|
119
|
+
* DI token for {@link IAskAgent}; consumed optionally by the git diff
|
|
120
|
+
* plugins so diffs still render when the plugin is disabled.
|
|
135
121
|
*/
|
|
136
122
|
export const IAskAgent = new Token<IAskAgent>(
|
|
137
123
|
'xtralab:IAskAgent',
|
package/src/commandBar/index.ts
CHANGED
|
@@ -12,25 +12,13 @@ import { IOmnibox, OMNIBOX_OPEN_COMMAND } from '../omnibox/tokens';
|
|
|
12
12
|
|
|
13
13
|
const PLUGIN_ID = 'xtralab:command-bar';
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Factory name of JupyterLab's settings-driven top bar toolbar (`#jp-top-bar`,
|
|
17
|
-
* built by `@jupyterlab/application-extension:top-bar`).
|
|
18
|
-
*/
|
|
19
15
|
const TOPBAR_FACTORY = 'TopBar';
|
|
20
16
|
|
|
21
|
-
/**
|
|
22
|
-
* Name of the pill item within that toolbar. Its placement is declared under
|
|
23
|
-
* `jupyter.lab.toolbars` in this plugin's settings schema
|
|
24
|
-
* (schema/command-bar.json): the core toolbar ships a spacer at rank 50, so
|
|
25
|
-
* the pill's higher rank lands it at the trailing end of the toolbar, next to
|
|
26
|
-
* the right-sidebar toggle button.
|
|
27
|
-
*/
|
|
28
17
|
const ITEM_NAME = 'omnibox';
|
|
29
18
|
|
|
30
19
|
/**
|
|
31
|
-
* A search-bar-styled launcher pill
|
|
32
|
-
*
|
|
33
|
-
* which opens the omnibox.
|
|
20
|
+
* A search-bar-styled launcher pill with no input of its own: activating it
|
|
21
|
+
* runs `onActivate`, which opens the omnibox.
|
|
34
22
|
*/
|
|
35
23
|
class CommandBar extends Widget {
|
|
36
24
|
constructor(options: CommandBar.IOptions) {
|
|
@@ -45,19 +33,26 @@ class CommandBar extends Widget {
|
|
|
45
33
|
this._onActivate = options.onActivate;
|
|
46
34
|
}
|
|
47
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Handle the DOM events for the command bar.
|
|
38
|
+
*/
|
|
48
39
|
handleEvent(event: Event): void {
|
|
49
40
|
if (event.type === 'click') {
|
|
50
41
|
this._onActivate();
|
|
51
42
|
}
|
|
52
43
|
}
|
|
53
44
|
|
|
45
|
+
/**
|
|
46
|
+
* A message handler invoked on an `'after-attach'` message.
|
|
47
|
+
*/
|
|
54
48
|
protected onAfterAttach(): void {
|
|
55
|
-
//
|
|
56
|
-
// listened on here; keyboard Enter/Space on the focused button raises the
|
|
57
|
-
// same synthetic click.
|
|
49
|
+
// Keyboard Enter/Space on the focused button raises the same synthetic click.
|
|
58
50
|
this.node.addEventListener('click', this);
|
|
59
51
|
}
|
|
60
52
|
|
|
53
|
+
/**
|
|
54
|
+
* A message handler invoked on a `'before-detach'` message.
|
|
55
|
+
*/
|
|
61
56
|
protected onBeforeDetach(): void {
|
|
62
57
|
this.node.removeEventListener('click', this);
|
|
63
58
|
}
|
|
@@ -66,6 +61,9 @@ class CommandBar extends Widget {
|
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
namespace CommandBar {
|
|
64
|
+
/**
|
|
65
|
+
* The options used to create a `CommandBar`.
|
|
66
|
+
*/
|
|
69
67
|
export interface IOptions {
|
|
70
68
|
/**
|
|
71
69
|
* Placeholder-style text shown inside the pill.
|
|
@@ -85,15 +83,16 @@ namespace CommandBar {
|
|
|
85
83
|
onActivate: () => void;
|
|
86
84
|
}
|
|
87
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Create the DOM node for a command bar.
|
|
88
|
+
*/
|
|
88
89
|
export function createNode(
|
|
89
90
|
label: string,
|
|
90
91
|
caption: string,
|
|
91
92
|
shortcut?: string
|
|
92
93
|
): HTMLElement {
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
// which would otherwise stretch the pill itself; the button inside keeps
|
|
96
|
-
// its own compact pill height.
|
|
94
|
+
// Plain wrapper: the core `.jp-Toolbar-item` sizing would otherwise
|
|
95
|
+
// stretch the pill itself.
|
|
97
96
|
const wrapper = document.createElement('div');
|
|
98
97
|
|
|
99
98
|
const button = document.createElement('button');
|
|
@@ -118,7 +117,6 @@ namespace CommandBar {
|
|
|
118
117
|
const hint = document.createElement('span');
|
|
119
118
|
hint.className = 'jp-xtralab-CommandBar-shortcut';
|
|
120
119
|
hint.textContent = shortcut;
|
|
121
|
-
// Decorative: the button's aria-label already names the action.
|
|
122
120
|
hint.setAttribute('aria-hidden', 'true');
|
|
123
121
|
button.appendChild(hint);
|
|
124
122
|
}
|
|
@@ -129,19 +127,10 @@ namespace CommandBar {
|
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
/**
|
|
132
|
-
* Contribute a search-bar-styled
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* The pill is a regular settings-driven toolbar item: this plugin registers a
|
|
137
|
-
* widget factory for it on the `IToolbarWidgetRegistry` and declares its rank
|
|
138
|
-
* in schema/command-bar.json, so users can move or disable it from the Top
|
|
139
|
-
* Bar settings like any other toolbar item.
|
|
140
|
-
*
|
|
141
|
-
* The factory is only registered when the omnibox is available — the
|
|
142
|
-
* `IOmnibox` token is provided by `xtralab:omnibox` — so the pill never
|
|
143
|
-
* appears with nothing to open (without a factory, the toolbar item resolves
|
|
144
|
-
* to an empty command button that renders nothing).
|
|
130
|
+
* Contribute a search-bar-styled pill to the top bar toolbar that opens the
|
|
131
|
+
* omnibox. It is a settings-driven toolbar item (factory here, rank in
|
|
132
|
+
* schema/command-bar.json) registered only when `IOmnibox` is provided —
|
|
133
|
+
* without a factory the item resolves to an empty button that renders nothing.
|
|
145
134
|
*/
|
|
146
135
|
const plugin: JupyterFrontEndPlugin<void> = {
|
|
147
136
|
id: PLUGIN_ID,
|
|
@@ -163,10 +152,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
163
152
|
const trans = (translator ?? nullTranslator).load('jupyterlab');
|
|
164
153
|
|
|
165
154
|
toolbarRegistry.addFactory(TOPBAR_FACTORY, ITEM_NAME, () => {
|
|
166
|
-
// Show the omnibox's keyboard shortcut as a hint in the pill, derived
|
|
167
|
-
// from the live binding (registered by xtralab:omnibox, which activates
|
|
168
|
-
// first as the IOmnibox provider) so it stays correct and uses the
|
|
169
|
-
// platform's modifier symbols. Empty when no binding is registered.
|
|
170
155
|
const binding = app.commands.keyBindings.find(
|
|
171
156
|
keyBinding => keyBinding.command === OMNIBOX_OPEN_COMMAND
|
|
172
157
|
);
|
package/src/customPanel/index.ts
CHANGED
|
@@ -31,23 +31,38 @@ class CustomPanel extends SidePanel implements IMovableSectionDestination {
|
|
|
31
31
|
this.addClass('jp-xtralab-CustomPanel');
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* The accordion panel hosting the sections.
|
|
36
|
+
*/
|
|
34
37
|
get accordionPanel(): AccordionPanel {
|
|
35
38
|
return this.content as AccordionPanel;
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
/**
|
|
42
|
+
* The section widgets currently hosted by the panel.
|
|
43
|
+
*/
|
|
38
44
|
get sections(): ReadonlyArray<Widget> {
|
|
39
45
|
return this.content.widgets;
|
|
40
46
|
}
|
|
41
47
|
|
|
48
|
+
/**
|
|
49
|
+
* A signal emitted with the new count when the number of sections changes.
|
|
50
|
+
*/
|
|
42
51
|
get sectionCountChanged(): ISignal<this, number> {
|
|
43
52
|
return this._sectionCountChanged;
|
|
44
53
|
}
|
|
45
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Add a section widget to the panel.
|
|
57
|
+
*/
|
|
46
58
|
addSection(widget: Widget): void {
|
|
47
59
|
this.addWidget(widget);
|
|
48
60
|
this._sectionCountChanged.emit(this.content.widgets.length);
|
|
49
61
|
}
|
|
50
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Remove a section widget from the panel, if it is hosted here.
|
|
65
|
+
*/
|
|
51
66
|
removeSectionWidget(widget: Widget): void {
|
|
52
67
|
if (widget.parent !== this.content) {
|
|
53
68
|
return;
|