xtralab 0.11.1 → 0.12.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.
- package/README.md +38 -231
- package/lib/agentSessions.d.ts +6 -2
- package/lib/askAgent/editorSelection.d.ts +53 -0
- package/lib/askAgent/editorSelection.js +95 -0
- package/lib/askAgent/icons.d.ts +7 -0
- package/lib/askAgent/icons.js +15 -0
- package/lib/askAgent/index.d.ts +32 -0
- package/lib/askAgent/index.js +741 -0
- package/lib/askAgent/popup.d.ts +83 -0
- package/lib/askAgent/popup.js +221 -0
- package/lib/askAgent/prompt.d.ts +24 -0
- package/lib/askAgent/prompt.js +116 -0
- package/lib/askAgent/queue.d.ts +93 -0
- package/lib/askAgent/queue.js +207 -0
- package/lib/askAgent/queuePanel.d.ts +76 -0
- package/lib/askAgent/queuePanel.js +188 -0
- package/lib/askAgent/targetPicker.d.ts +58 -0
- package/lib/askAgent/targetPicker.js +74 -0
- package/lib/askAgent/tokens.d.ts +124 -0
- package/lib/askAgent/tokens.js +13 -0
- package/lib/commandBar/index.d.ts +12 -8
- package/lib/commandBar/index.js +58 -41
- package/lib/editorBreadcrumbs/index.js +9 -4
- package/lib/editorBreadcrumbs/widget.d.ts +7 -7
- package/lib/editorBreadcrumbs/widget.js +6 -8
- package/lib/fileBrowser/commands.d.ts +2 -8
- package/lib/fileBrowser/commands.js +39 -30
- package/lib/fileBrowser/contents.d.ts +8 -3
- package/lib/fileBrowser/fileBrowser.d.ts +2 -1
- package/lib/fileBrowser/widget.d.ts +5 -9
- package/lib/fileBrowser/widget.js +1 -1
- package/lib/fileTypeIcons/index.js +5 -2
- package/lib/git/api.d.ts +0 -26
- package/lib/git/api.js +2 -44
- package/lib/git/askRequest.d.ts +23 -0
- package/lib/git/askRequest.js +90 -0
- package/lib/git/commands.d.ts +14 -2
- package/lib/git/commands.js +16 -13
- package/lib/git/diffModel.d.ts +1 -9
- package/lib/git/diffModel.js +1 -1
- package/lib/git/diffProvider.js +8 -3
- package/lib/git/diffSurface.d.ts +19 -2
- package/lib/git/diffSurface.js +64 -18
- package/lib/git/diffTheme.d.ts +0 -4
- package/lib/git/diffTheme.js +1 -1
- package/lib/git/diffWidget.d.ts +9 -0
- package/lib/git/diffWidget.js +38 -10
- package/lib/git/imageDiff.d.ts +17 -4
- package/lib/git/imageDiff.js +90 -30
- package/lib/git/index.js +7 -2
- package/lib/git/notebookDiff.d.ts +10 -67
- package/lib/git/notebookDiff.js +62 -69
- package/lib/git/tokens.d.ts +5 -2
- package/lib/highlight/index.js +12 -8
- package/lib/index.js +2 -0
- package/lib/launcher/agents.js +3 -4
- package/lib/launcher/commands.d.ts +6 -2
- package/lib/launcher/dashboard.d.ts +8 -1
- package/lib/launcher/dashboard.js +39 -33
- package/lib/launcher/editorRegistry.js +5 -3
- package/lib/launcher/editors.d.ts +15 -5
- package/lib/launcher/icons.d.ts +0 -37
- package/lib/launcher/icons.js +11 -12
- package/lib/launcher/index.js +2 -1
- package/lib/launcher/invocation.d.ts +0 -15
- package/lib/launcher/invocation.js +1 -1
- package/lib/launcher/schemaDefaults.d.ts +3 -1
- package/lib/launcher/schemaDefaults.js +3 -1
- package/lib/mimeData.d.ts +7 -0
- package/lib/mimeData.js +16 -0
- package/lib/omnibox/index.d.ts +4 -0
- package/lib/omnibox/index.js +43 -2
- package/lib/omnibox/model.d.ts +43 -14
- package/lib/omnibox/model.js +117 -14
- package/lib/omnibox/recents.d.ts +65 -0
- package/lib/omnibox/recents.js +109 -0
- package/lib/omnibox/tokens.d.ts +6 -2
- package/lib/omnibox/widget.d.ts +23 -6
- package/lib/omnibox/widget.js +26 -7
- package/lib/showOutput/index.js +15 -18
- package/lib/terminals/agentTerminals.d.ts +63 -0
- package/lib/terminals/agentTerminals.js +157 -0
- package/lib/terminals/index.d.ts +7 -1
- package/lib/terminals/index.js +50 -30
- package/lib/terminals/model.d.ts +11 -2
- package/lib/terminals/model.js +27 -8
- package/lib/terminals/tokens.d.ts +66 -0
- package/lib/terminals/tokens.js +7 -0
- package/lib/terminals/widget.d.ts +3 -6
- package/lib/terminals/widget.js +1 -1
- package/lib/topBar/index.js +3 -3
- package/lib/walkthrough/index.js +14 -3
- package/lib/walkthrough/panel.d.ts +12 -4
- package/lib/walkthrough/panel.js +9 -3
- package/package.json +49 -51
- package/schema/command-bar.json +10 -0
- package/schema/omnibox.json +15 -0
- package/src/agentSessions.ts +6 -2
- package/src/askAgent/editorSelection.ts +138 -0
- package/src/askAgent/icons.ts +16 -0
- package/src/askAgent/index.ts +915 -0
- package/src/askAgent/popup.tsx +407 -0
- package/src/askAgent/prompt.ts +144 -0
- package/src/askAgent/queue.ts +269 -0
- package/src/askAgent/queuePanel.tsx +418 -0
- package/src/askAgent/targetPicker.tsx +209 -0
- package/src/askAgent/tokens.ts +139 -0
- package/src/commandBar/index.ts +75 -49
- package/src/editorBreadcrumbs/index.ts +14 -4
- package/src/editorBreadcrumbs/widget.ts +11 -9
- package/src/fileBrowser/commands.ts +45 -31
- package/src/fileBrowser/contents.ts +7 -3
- package/src/fileBrowser/fileBrowser.tsx +1 -1
- package/src/fileBrowser/widget.tsx +5 -3
- package/src/fileTypeIcons/index.ts +6 -3
- package/src/git/api.ts +2 -61
- package/src/git/askRequest.ts +113 -0
- package/src/git/commands.ts +41 -14
- package/src/git/diffModel.ts +1 -1
- package/src/git/diffProvider.tsx +11 -3
- package/src/git/diffSurface.tsx +114 -22
- package/src/git/diffTheme.ts +1 -1
- package/src/git/diffWidget.tsx +54 -7
- package/src/git/imageDiff.tsx +169 -58
- package/src/git/index.ts +10 -2
- package/src/git/notebookDiff.tsx +91 -57
- package/src/git/tokens.ts +4 -2
- package/src/highlight/index.ts +12 -8
- package/src/index.ts +2 -0
- package/src/launcher/agents.ts +3 -4
- package/src/launcher/commands.ts +6 -2
- package/src/launcher/dashboard.tsx +86 -38
- package/src/launcher/editorRegistry.ts +10 -4
- package/src/launcher/editors.ts +15 -5
- package/src/launcher/icons.ts +11 -12
- package/src/launcher/index.ts +2 -1
- package/src/launcher/invocation.ts +1 -1
- package/src/launcher/schemaDefaults.ts +3 -1
- package/src/mimeData.ts +20 -0
- package/src/omnibox/index.ts +48 -1
- package/src/omnibox/model.ts +173 -33
- package/src/omnibox/recents.ts +155 -0
- package/src/omnibox/tokens.ts +6 -2
- package/src/omnibox/widget.tsx +54 -13
- package/src/showOutput/index.ts +20 -23
- package/src/terminals/agentTerminals.ts +238 -0
- package/src/terminals/index.ts +54 -30
- package/src/terminals/model.ts +28 -7
- package/src/terminals/tokens.ts +77 -0
- package/src/terminals/widget.tsx +4 -2
- package/src/topBar/index.ts +12 -6
- package/src/walkthrough/index.ts +19 -4
- package/src/walkthrough/panel.ts +15 -5
- package/style/askAgent.css +544 -0
- package/style/commandBar.css +12 -33
- package/style/git.css +72 -31
- package/style/index.css +1 -0
- package/style/index.js +2 -0
- package/style/topBar.css +4 -4
|
@@ -4,6 +4,7 @@ import type { CommandRegistry } from '@lumino/commands';
|
|
|
4
4
|
import type { ReadonlyPartialJSONObject } from '@lumino/coreutils';
|
|
5
5
|
import { Poll } from '@lumino/polling';
|
|
6
6
|
import type { IDocumentWidget } from '@jupyterlab/docregistry';
|
|
7
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
7
8
|
import {
|
|
8
9
|
LabIcon,
|
|
9
10
|
ReactWidget,
|
|
@@ -38,7 +39,7 @@ import { agentCommandId } from './tokens';
|
|
|
38
39
|
* tab for the freshly created terminal). Keeping it as an opaque
|
|
39
40
|
* callback means the widget itself does not import `app.shell`.
|
|
40
41
|
*/
|
|
41
|
-
|
|
42
|
+
interface ILauncherDashboardOptions {
|
|
42
43
|
commands: CommandRegistry;
|
|
43
44
|
/**
|
|
44
45
|
* The agent list to render. Already filtered by availability + sorted by
|
|
@@ -74,6 +75,11 @@ export interface ILauncherDashboardOptions {
|
|
|
74
75
|
* Empty string lets the terminal extension default to the server root.
|
|
75
76
|
*/
|
|
76
77
|
cwd: string;
|
|
78
|
+
/**
|
|
79
|
+
* The translation bundle used to localize the dashboard's user-facing
|
|
80
|
+
* strings.
|
|
81
|
+
*/
|
|
82
|
+
trans: TranslationBundle;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/**
|
|
@@ -125,7 +131,8 @@ function LauncherDashboardComponent(
|
|
|
125
131
|
agentSessions,
|
|
126
132
|
onAgentLaunch,
|
|
127
133
|
repoPath,
|
|
128
|
-
cwd
|
|
134
|
+
cwd,
|
|
135
|
+
trans
|
|
129
136
|
} = props;
|
|
130
137
|
const [prompt, setPrompt] = React.useState('');
|
|
131
138
|
const [git, setGit] = React.useState<IGitState>({
|
|
@@ -264,19 +271,22 @@ function LauncherDashboardComponent(
|
|
|
264
271
|
prompt={prompt}
|
|
265
272
|
onPromptChange={setPrompt}
|
|
266
273
|
onLaunch={launch}
|
|
274
|
+
trans={trans}
|
|
267
275
|
/>
|
|
268
|
-
<McpSection agents={agents} />
|
|
276
|
+
<McpSection agents={agents} trans={trans} />
|
|
269
277
|
<OpenSection
|
|
270
278
|
editor={editor}
|
|
271
279
|
onLaunchTerminal={launchTerminal}
|
|
272
280
|
onLaunchNotebook={launchNotebook}
|
|
273
281
|
onLaunchConsole={launchConsole}
|
|
274
282
|
onLaunchEditor={launchEditor}
|
|
283
|
+
trans={trans}
|
|
275
284
|
/>
|
|
276
285
|
<ChangesSection
|
|
277
286
|
git={git}
|
|
278
287
|
onOpen={openDiff}
|
|
279
288
|
onRefresh={() => void refresh()}
|
|
289
|
+
trans={trans}
|
|
280
290
|
/>
|
|
281
291
|
</div>
|
|
282
292
|
);
|
|
@@ -286,8 +296,9 @@ function ChangesSection(props: {
|
|
|
286
296
|
git: IGitState;
|
|
287
297
|
onOpen: (change: IFileChange) => void;
|
|
288
298
|
onRefresh: () => void;
|
|
299
|
+
trans: TranslationBundle;
|
|
289
300
|
}): React.ReactElement {
|
|
290
|
-
const { git, onOpen, onRefresh } = props;
|
|
301
|
+
const { git, onOpen, onRefresh, trans } = props;
|
|
291
302
|
const files = git.result ? expandStatusFiles(git.result.files) : [];
|
|
292
303
|
|
|
293
304
|
// Native `<details>` rather than a hand-rolled toggle: we get the
|
|
@@ -300,11 +311,17 @@ function ChangesSection(props: {
|
|
|
300
311
|
open
|
|
301
312
|
>
|
|
302
313
|
<summary className="jp-xtralab-Launcher-section-summary">
|
|
303
|
-
<span className="jp-xtralab-Launcher-section-title">
|
|
314
|
+
<span className="jp-xtralab-Launcher-section-title">
|
|
315
|
+
{trans.__('Changes')}
|
|
316
|
+
</span>
|
|
304
317
|
{files.length > 0 && (
|
|
305
318
|
<span
|
|
306
319
|
className="jp-xtralab-Launcher-section-count"
|
|
307
|
-
aria-label={
|
|
320
|
+
aria-label={trans._n(
|
|
321
|
+
'%1 changed file',
|
|
322
|
+
'%1 changed files',
|
|
323
|
+
files.length
|
|
324
|
+
)}
|
|
308
325
|
>
|
|
309
326
|
{files.length}
|
|
310
327
|
</span>
|
|
@@ -312,7 +329,7 @@ function ChangesSection(props: {
|
|
|
312
329
|
<button
|
|
313
330
|
type="button"
|
|
314
331
|
className="jp-xtralab-Launcher-section-action"
|
|
315
|
-
aria-label=
|
|
332
|
+
aria-label={trans.__('Refresh changes')}
|
|
316
333
|
// Stop the click from toggling the surrounding `<details>` —
|
|
317
334
|
// refreshing while the section is open shouldn't collapse it.
|
|
318
335
|
onClick={event => {
|
|
@@ -326,13 +343,13 @@ function ChangesSection(props: {
|
|
|
326
343
|
</summary>
|
|
327
344
|
<div className="jp-xtralab-Launcher-section-body">
|
|
328
345
|
{git.loading && files.length === 0 && (
|
|
329
|
-
<p className="jp-xtralab-Launcher-empty">Loading
|
|
346
|
+
<p className="jp-xtralab-Launcher-empty">{trans.__('Loading…')}</p>
|
|
330
347
|
)}
|
|
331
348
|
{!git.loading && git.error !== null && (
|
|
332
349
|
<p className="jp-xtralab-Launcher-empty">{git.error}</p>
|
|
333
350
|
)}
|
|
334
351
|
{!git.loading && git.error === null && files.length === 0 && (
|
|
335
|
-
<p className="jp-xtralab-Launcher-empty">No changes
|
|
352
|
+
<p className="jp-xtralab-Launcher-empty">{trans.__('No changes.')}</p>
|
|
336
353
|
)}
|
|
337
354
|
{files.length > 0 && (
|
|
338
355
|
<ul className="jp-xtralab-Launcher-changes">
|
|
@@ -342,7 +359,7 @@ function ChangesSection(props: {
|
|
|
342
359
|
type="button"
|
|
343
360
|
className="jp-xtralab-Launcher-change"
|
|
344
361
|
onClick={() => onOpen(change)}
|
|
345
|
-
title={
|
|
362
|
+
title={trans.__('Open diff for %1', change.path)}
|
|
346
363
|
>
|
|
347
364
|
<span
|
|
348
365
|
className={`jp-xtralab-Launcher-change-badge jp-xtralab-Launcher-change-${change.status}`}
|
|
@@ -357,7 +374,7 @@ function ChangesSection(props: {
|
|
|
357
374
|
className="jp-xtralab-Launcher-change-group"
|
|
358
375
|
aria-hidden="true"
|
|
359
376
|
>
|
|
360
|
-
{change.group === 'staged' ? 'staged' : ''}
|
|
377
|
+
{change.group === 'staged' ? trans.__('staged') : ''}
|
|
361
378
|
</span>
|
|
362
379
|
</button>
|
|
363
380
|
</li>
|
|
@@ -395,8 +412,9 @@ function AgentSection(props: {
|
|
|
395
412
|
prompt: string;
|
|
396
413
|
onPromptChange: (value: string) => void;
|
|
397
414
|
onLaunch: (agent: IAgent) => void;
|
|
415
|
+
trans: TranslationBundle;
|
|
398
416
|
}): React.ReactElement {
|
|
399
|
-
const { agents, prompt, onPromptChange, onLaunch } = props;
|
|
417
|
+
const { agents, prompt, onPromptChange, onLaunch, trans } = props;
|
|
400
418
|
const trimmed = prompt.trim();
|
|
401
419
|
const promptActive = trimmed.length > 0;
|
|
402
420
|
// The first prompt-capable agent is what Cmd/Ctrl+Enter fires; the hint
|
|
@@ -407,10 +425,14 @@ function AgentSection(props: {
|
|
|
407
425
|
|
|
408
426
|
return (
|
|
409
427
|
<section className="jp-xtralab-Launcher-section">
|
|
410
|
-
<h2 className="jp-xtralab-Launcher-section-title">
|
|
428
|
+
<h2 className="jp-xtralab-Launcher-section-title">
|
|
429
|
+
{trans.__('Start an agent')}
|
|
430
|
+
</h2>
|
|
411
431
|
<textarea
|
|
412
432
|
className="jp-xtralab-Launcher-prompt"
|
|
413
|
-
placeholder=
|
|
433
|
+
placeholder={trans.__(
|
|
434
|
+
'Initial prompt (optional) — passed to the selected agent.'
|
|
435
|
+
)}
|
|
414
436
|
value={prompt}
|
|
415
437
|
spellCheck={false}
|
|
416
438
|
rows={3}
|
|
@@ -433,15 +455,23 @@ function AgentSection(props: {
|
|
|
433
455
|
aria-live="polite"
|
|
434
456
|
>
|
|
435
457
|
{promptActive
|
|
436
|
-
?
|
|
437
|
-
|
|
458
|
+
? trans.__(
|
|
459
|
+
"Cmd/Ctrl+Enter launches %1. Agents that don't accept an initial prompt are dimmed.",
|
|
460
|
+
primaryAgent?.label ?? trans.__('the first prompt-capable agent')
|
|
461
|
+
)
|
|
462
|
+
: trans.__(
|
|
463
|
+
'Type a prompt to send it to the chosen agent. Some agents only launch without a prompt.'
|
|
464
|
+
)}
|
|
438
465
|
</p>
|
|
439
466
|
<div className="jp-xtralab-Launcher-agents">
|
|
440
467
|
{agents.map(agent => {
|
|
441
468
|
const supportsPrompt = agent.promptArgs !== undefined;
|
|
442
469
|
const disabled = promptActive && !supportsPrompt;
|
|
443
470
|
const tooltip = disabled
|
|
444
|
-
?
|
|
471
|
+
? trans.__(
|
|
472
|
+
"%1 doesn't accept an initial prompt — clear the prompt to launch.",
|
|
473
|
+
agent.label
|
|
474
|
+
)
|
|
445
475
|
: agent.caption;
|
|
446
476
|
return (
|
|
447
477
|
<button
|
|
@@ -478,7 +508,9 @@ function AgentSection(props: {
|
|
|
478
508
|
*/
|
|
479
509
|
const MCP_ADD_AGENT_IDS = new Set(['claude', 'codex', 'copilot']);
|
|
480
510
|
|
|
481
|
-
/**
|
|
511
|
+
/**
|
|
512
|
+
* The stdio proxy console script that bridges an agent to the MCP server.
|
|
513
|
+
*/
|
|
482
514
|
const MCP_PROXY_COMMAND = 'jupyter-server-mcp-proxy';
|
|
483
515
|
|
|
484
516
|
/**
|
|
@@ -515,7 +547,11 @@ function legacyCopy(text: string): boolean {
|
|
|
515
547
|
* proxy discover the server from its runtime file. Renders nothing when none
|
|
516
548
|
* of those agents are on `$PATH`.
|
|
517
549
|
*/
|
|
518
|
-
function McpSection(props: {
|
|
550
|
+
function McpSection(props: {
|
|
551
|
+
agents: IAgent[];
|
|
552
|
+
trans: TranslationBundle;
|
|
553
|
+
}): React.ReactElement | null {
|
|
554
|
+
const { trans } = props;
|
|
519
555
|
const [copiedId, setCopiedId] = React.useState<string | null>(null);
|
|
520
556
|
const registerable = props.agents.filter(agent =>
|
|
521
557
|
MCP_ADD_AGENT_IDS.has(agent.id)
|
|
@@ -555,13 +591,14 @@ function McpSection(props: { agents: IAgent[] }): React.ReactElement | null {
|
|
|
555
591
|
<details className="jp-xtralab-Launcher-section jp-xtralab-Launcher-mcp-section">
|
|
556
592
|
<summary className="jp-xtralab-Launcher-section-summary">
|
|
557
593
|
<span className="jp-xtralab-Launcher-section-title">
|
|
558
|
-
Connect agents to JupyterLab (MCP)
|
|
594
|
+
{trans.__('Connect agents to JupyterLab (MCP)')}
|
|
559
595
|
</span>
|
|
560
596
|
</summary>
|
|
561
597
|
<div className="jp-xtralab-Launcher-section-body">
|
|
562
598
|
<p className="jp-xtralab-Launcher-agent-hint">
|
|
563
|
-
|
|
564
|
-
|
|
599
|
+
{trans.__(
|
|
600
|
+
'Run once per agent to let it drive this JupyterLab over MCP. No port needed — the proxy finds this server on its own.'
|
|
601
|
+
)}
|
|
565
602
|
</p>
|
|
566
603
|
<ul className="jp-xtralab-Launcher-mcp-list">
|
|
567
604
|
{registerable.map(agent => {
|
|
@@ -578,19 +615,22 @@ function McpSection(props: { agents: IAgent[] }): React.ReactElement | null {
|
|
|
578
615
|
? 'jp-xtralab-Launcher-mcp-copy jp-mod-copied'
|
|
579
616
|
: 'jp-xtralab-Launcher-mcp-copy'
|
|
580
617
|
}
|
|
581
|
-
aria-label={
|
|
618
|
+
aria-label={trans.__('Copy the %1 command', agent.label)}
|
|
582
619
|
onClick={() => copy(command, agent.id)}
|
|
583
620
|
>
|
|
584
|
-
{copiedId === agent.id
|
|
621
|
+
{copiedId === agent.id
|
|
622
|
+
? trans.__('Copied!')
|
|
623
|
+
: trans.__('Copy')}
|
|
585
624
|
</button>
|
|
586
625
|
</li>
|
|
587
626
|
);
|
|
588
627
|
})}
|
|
589
628
|
</ul>
|
|
590
629
|
<p className="jp-xtralab-Launcher-mcp-note">
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
630
|
+
{trans.__(
|
|
631
|
+
'Other agents (Goose, OpenCode, Kiro, Mistral Vibe, Antigravity) register MCP through their own config — point them at the same'
|
|
632
|
+
)}{' '}
|
|
633
|
+
<code>{MCP_PROXY_COMMAND}</code> {trans.__('command.')}
|
|
594
634
|
</p>
|
|
595
635
|
</div>
|
|
596
636
|
</details>
|
|
@@ -615,23 +655,25 @@ function OpenSection(props: {
|
|
|
615
655
|
onLaunchNotebook: () => void;
|
|
616
656
|
onLaunchConsole: () => void;
|
|
617
657
|
onLaunchEditor: () => void;
|
|
658
|
+
trans: TranslationBundle;
|
|
618
659
|
}): React.ReactElement {
|
|
619
660
|
const {
|
|
620
661
|
editor,
|
|
621
662
|
onLaunchTerminal,
|
|
622
663
|
onLaunchNotebook,
|
|
623
664
|
onLaunchConsole,
|
|
624
|
-
onLaunchEditor
|
|
665
|
+
onLaunchEditor,
|
|
666
|
+
trans
|
|
625
667
|
} = props;
|
|
626
668
|
return (
|
|
627
669
|
<section className="jp-xtralab-Launcher-section">
|
|
628
|
-
<h2 className="jp-xtralab-Launcher-section-title">Open</h2>
|
|
670
|
+
<h2 className="jp-xtralab-Launcher-section-title">{trans.__('Open')}</h2>
|
|
629
671
|
<div className="jp-xtralab-Launcher-agents">
|
|
630
672
|
<button
|
|
631
673
|
type="button"
|
|
632
674
|
className="jp-xtralab-Launcher-agent"
|
|
633
|
-
title=
|
|
634
|
-
aria-label=
|
|
675
|
+
title={trans.__('Open a new terminal.')}
|
|
676
|
+
aria-label={trans.__('Open a new terminal')}
|
|
635
677
|
onClick={onLaunchTerminal}
|
|
636
678
|
>
|
|
637
679
|
<LabIcon.resolveReact
|
|
@@ -639,13 +681,15 @@ function OpenSection(props: {
|
|
|
639
681
|
tag="span"
|
|
640
682
|
className="jp-xtralab-Launcher-agent-icon"
|
|
641
683
|
/>
|
|
642
|
-
<span className="jp-xtralab-Launcher-agent-label">
|
|
684
|
+
<span className="jp-xtralab-Launcher-agent-label">
|
|
685
|
+
{trans.__('Terminal')}
|
|
686
|
+
</span>
|
|
643
687
|
</button>
|
|
644
688
|
<button
|
|
645
689
|
type="button"
|
|
646
690
|
className="jp-xtralab-Launcher-agent"
|
|
647
|
-
title=
|
|
648
|
-
aria-label=
|
|
691
|
+
title={trans.__('Create a new notebook.')}
|
|
692
|
+
aria-label={trans.__('Create a new notebook')}
|
|
649
693
|
onClick={onLaunchNotebook}
|
|
650
694
|
>
|
|
651
695
|
<LabIcon.resolveReact
|
|
@@ -653,13 +697,15 @@ function OpenSection(props: {
|
|
|
653
697
|
tag="span"
|
|
654
698
|
className="jp-xtralab-Launcher-agent-icon"
|
|
655
699
|
/>
|
|
656
|
-
<span className="jp-xtralab-Launcher-agent-label">
|
|
700
|
+
<span className="jp-xtralab-Launcher-agent-label">
|
|
701
|
+
{trans.__('Notebook')}
|
|
702
|
+
</span>
|
|
657
703
|
</button>
|
|
658
704
|
<button
|
|
659
705
|
type="button"
|
|
660
706
|
className="jp-xtralab-Launcher-agent"
|
|
661
|
-
title=
|
|
662
|
-
aria-label=
|
|
707
|
+
title={trans.__('Create a new console.')}
|
|
708
|
+
aria-label={trans.__('Create a new console')}
|
|
663
709
|
onClick={onLaunchConsole}
|
|
664
710
|
>
|
|
665
711
|
<LabIcon.resolveReact
|
|
@@ -667,7 +713,9 @@ function OpenSection(props: {
|
|
|
667
713
|
tag="span"
|
|
668
714
|
className="jp-xtralab-Launcher-agent-icon"
|
|
669
715
|
/>
|
|
670
|
-
<span className="jp-xtralab-Launcher-agent-label">
|
|
716
|
+
<span className="jp-xtralab-Launcher-agent-label">
|
|
717
|
+
{trans.__('Console')}
|
|
718
|
+
</span>
|
|
671
719
|
</button>
|
|
672
720
|
{editor && (
|
|
673
721
|
<button
|
|
@@ -72,7 +72,9 @@ class EditorRegistry implements IEditorRegistry {
|
|
|
72
72
|
return this._changed;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Replace both lists (recomputed together) and notify observers.
|
|
77
|
+
*/
|
|
76
78
|
set(editors: IEditor[], current: IEditor | null): void {
|
|
77
79
|
this._editors = editors;
|
|
78
80
|
this._current = current;
|
|
@@ -110,9 +112,13 @@ export const editorRegistryPlugin: JupyterFrontEndPlugin<IEditorRegistry> = {
|
|
|
110
112
|
// Probe only the editors that opt into the availability check; entries
|
|
111
113
|
// with `requireAvailable: false` (e.g. a shell alias) are shown
|
|
112
114
|
// regardless and don't need a `which` lookup.
|
|
113
|
-
const probe =
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
const probe = Array.from(
|
|
116
|
+
new Set(
|
|
117
|
+
editors
|
|
118
|
+
.filter(editor => editor.requireAvailable)
|
|
119
|
+
.map(editor => editor.command)
|
|
120
|
+
)
|
|
121
|
+
);
|
|
116
122
|
const available = await fetchAvailableCommands(probe);
|
|
117
123
|
registry.set(editors, resolveEditor(editors, available));
|
|
118
124
|
};
|
package/src/launcher/editors.ts
CHANGED
|
@@ -10,15 +10,25 @@ import { BUILTIN_EDITOR_ICONS } from './icons';
|
|
|
10
10
|
* the terminals panel to badge running editors.
|
|
11
11
|
*/
|
|
12
12
|
export interface IEditor {
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Stable id; also the default `$PATH` command probed for availability.
|
|
15
|
+
*/
|
|
14
16
|
id: string;
|
|
15
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Tile label, e.g. "Neovim".
|
|
19
|
+
*/
|
|
16
20
|
label: string;
|
|
17
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Tile tooltip.
|
|
23
|
+
*/
|
|
18
24
|
caption: string;
|
|
19
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* The literal command typed into the new terminal, e.g. `nvim`.
|
|
27
|
+
*/
|
|
20
28
|
command: string;
|
|
21
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Brand icon for the tile.
|
|
31
|
+
*/
|
|
22
32
|
icon: LabIcon;
|
|
23
33
|
/**
|
|
24
34
|
* Preference order for the single launcher tile: the first candidate, by
|
package/src/launcher/icons.ts
CHANGED
|
@@ -6,8 +6,7 @@ import { LabIcon } from '@jupyterlab/ui-components';
|
|
|
6
6
|
* (`jupyter_ai_acp_client/static/*.svg`, BSD-3-Clause); Antigravity post-dates
|
|
7
7
|
* that set, so its mark is the official glyph from `@lobehub/icons-static-svg`
|
|
8
8
|
* (MIT) — we ship the brand-colored `antigravity-color` variant so Antigravity
|
|
9
|
-
* reads as a multi-color Google mark
|
|
10
|
-
* to fill before the upstream Gemini CLI sunset. Small adjustments are applied
|
|
9
|
+
* reads as a multi-color Google mark. Small adjustments are applied
|
|
11
10
|
* to play nicely with JupyterLab themes:
|
|
12
11
|
* - Monochrome marks (Codex, Copilot, Goose) use `currentColor` so they
|
|
13
12
|
* inherit the surrounding launcher card's text color rather than
|
|
@@ -28,7 +27,7 @@ import { LabIcon } from '@jupyterlab/ui-components';
|
|
|
28
27
|
* reads on both the light and dark themes.
|
|
29
28
|
*/
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
const antigravityIcon = new LabIcon({
|
|
32
31
|
name: 'xtralab:agent-antigravity',
|
|
33
32
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
34
33
|
<mask id="xtralab-antigravity-mask" height="23" maskUnits="userSpaceOnUse" width="24" x="0" y="1">
|
|
@@ -107,21 +106,21 @@ export const antigravityIcon = new LabIcon({
|
|
|
107
106
|
</svg>`
|
|
108
107
|
});
|
|
109
108
|
|
|
110
|
-
|
|
109
|
+
const claudeIcon = new LabIcon({
|
|
111
110
|
name: 'xtralab:agent-claude',
|
|
112
111
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200">
|
|
113
112
|
<path fill="#d97757" d="M 233.959793 800.214905 L 468.644287 668.536987 L 472.590637 657.100647 L 468.644287 650.738403 L 457.208069 650.738403 L 417.986633 648.322144 L 283.892639 644.69812 L 167.597321 639.865845 L 54.926208 633.825623 L 26.577238 627.785339 L 3.3e-05 592.751709 L 2.73832 575.27533 L 26.577238 559.248352 L 60.724873 562.228149 L 136.187973 567.382629 L 249.422867 575.194763 L 331.570496 580.026978 L 453.261841 592.671082 L 472.590637 592.671082 L 475.328857 584.859009 L 468.724915 580.026978 L 463.570557 575.194763 L 346.389313 495.785217 L 219.543671 411.865906 L 153.100723 363.543762 L 117.181267 339.060425 L 99.060455 316.107361 L 91.248367 266.01355 L 123.865784 230.093994 L 167.677887 233.073853 L 178.872513 236.053772 L 223.248367 270.201477 L 318.040283 343.570496 L 441.825592 434.738342 L 459.946411 449.798706 L 467.194672 444.64447 L 468.080597 441.020203 L 459.946411 427.409485 L 392.617493 305.718323 L 320.778564 181.932983 L 288.80542 130.630859 L 280.348999 99.865845 C 277.369171 87.221436 275.194641 76.590698 275.194641 63.624268 L 312.322174 13.20813 L 332.8591 6.604126 L 382.389313 13.20813 L 403.248352 31.328979 L 434.013519 101.71814 L 483.865753 212.537048 L 561.181274 363.221497 L 583.812134 407.919434 L 595.892639 449.315491 L 600.40271 461.959839 L 608.214783 461.959839 L 608.214783 454.711609 L 614.577271 369.825623 L 626.335632 265.61084 L 637.771851 131.516846 L 641.718201 93.745117 L 660.402832 48.483276 L 697.530334 24.000122 L 726.52356 37.852417 L 750.362549 72 L 747.060486 94.067139 L 732.886047 186.201416 L 705.100708 330.52356 L 686.979919 427.167847 L 697.530334 427.167847 L 709.61084 415.087341 L 758.496704 350.174561 L 840.644348 247.490051 L 876.885925 206.738342 L 919.167847 161.71814 L 946.308838 140.29541 L 997.61084 140.29541 L 1035.38269 196.429626 L 1018.469849 254.416199 L 965.637634 321.422852 L 921.825562 378.201538 L 859.006714 462.765259 L 819.785278 530.41626 L 823.409424 535.812073 L 832.75177 534.92627 L 974.657776 504.724915 L 1051.328979 490.872559 L 1142.818848 475.167786 L 1184.214844 494.496582 L 1188.724854 514.147644 L 1172.456421 554.335693 L 1074.604126 578.496765 L 959.838989 601.449829 L 788.939636 641.879272 L 786.845764 643.409485 L 789.261841 646.389343 L 866.255127 653.637634 L 899.194702 655.409424 L 979.812134 655.409424 L 1129.932861 666.604187 L 1169.154419 692.537109 L 1192.671265 724.268677 L 1188.724854 748.429688 L 1128.322144 779.194641 L 1046.818848 759.865845 L 856.590759 714.604126 L 791.355774 698.335754 L 782.335693 698.335754 L 782.335693 703.731567 L 836.69812 756.885986 L 936.322205 846.845581 L 1061.073975 962.81897 L 1067.436279 991.490112 L 1051.409424 1014.120911 L 1034.496704 1011.704712 L 924.885986 929.234924 L 882.604126 892.107544 L 786.845764 811.48999 L 780.483276 811.48999 L 780.483276 819.946289 L 802.550415 852.241699 L 919.087341 1027.409424 L 925.127625 1081.127686 L 916.671204 1098.604126 L 886.469849 1109.154419 L 853.288696 1103.114136 L 785.073914 1007.355835 L 714.684631 899.516785 L 657.906067 802.872498 L 650.979858 806.81897 L 617.476624 1167.704834 L 601.771851 1186.147705 L 565.530212 1200 L 535.328857 1177.046997 L 519.302124 1139.919556 L 535.328857 1066.550537 L 554.657776 970.792053 L 570.362488 894.68457 L 584.536926 800.134277 L 592.993347 768.724976 L 592.429626 766.630859 L 585.503479 767.516968 L 514.22821 865.369263 L 405.825531 1011.865906 L 320.053711 1103.677979 L 299.516815 1111.812256 L 263.919525 1093.369263 L 267.221497 1060.429688 L 287.114136 1031.114136 L 405.825531 880.107361 L 477.422913 786.52356 L 523.651062 732.483276 L 523.328918 724.671265 L 520.590698 724.671265 L 205.288605 929.395935 L 149.154434 936.644409 L 124.993355 914.01355 L 127.973183 876.885986 L 139.409409 864.80542 L 234.201385 799.570435 L 233.879227 799.8927 Z"/>
|
|
114
113
|
</svg>`
|
|
115
114
|
});
|
|
116
115
|
|
|
117
|
-
|
|
116
|
+
const codexIcon = new LabIcon({
|
|
118
117
|
name: 'xtralab:agent-codex',
|
|
119
118
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
|
120
119
|
<path stroke="currentColor" stroke-linecap="round" stroke-width="2.484" d="M22.356 19.797H17.17M9.662 12.29l1.979 3.576a.511.511 0 0 1-.005.504l-1.974 3.409M30.758 16c0 8.15-6.607 14.758-14.758 14.758-8.15 0-14.758-6.607-14.758-14.758C1.242 7.85 7.85 1.242 16 1.242c8.15 0 14.758 6.608 14.758 14.758Z"/>
|
|
121
120
|
</svg>`
|
|
122
121
|
});
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
const copilotIcon = new LabIcon({
|
|
125
124
|
name: 'xtralab:agent-copilot',
|
|
126
125
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
|
|
127
126
|
<path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"/>
|
|
@@ -129,7 +128,7 @@ export const copilotIcon = new LabIcon({
|
|
|
129
128
|
</svg>`
|
|
130
129
|
});
|
|
131
130
|
|
|
132
|
-
|
|
131
|
+
const gooseIcon = new LabIcon({
|
|
133
132
|
name: 'xtralab:agent-goose',
|
|
134
133
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048">
|
|
135
134
|
<g transform="translate(128, 94) scale(3)" fill="currentColor">
|
|
@@ -138,7 +137,7 @@ export const gooseIcon = new LabIcon({
|
|
|
138
137
|
</svg>`
|
|
139
138
|
});
|
|
140
139
|
|
|
141
|
-
|
|
140
|
+
const kiroIcon = new LabIcon({
|
|
142
141
|
name: 'xtralab:agent-kiro',
|
|
143
142
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200" fill="none">
|
|
144
143
|
<rect width="1200" height="1200" rx="260" fill="#9046FF"/>
|
|
@@ -153,7 +152,7 @@ export const kiroIcon = new LabIcon({
|
|
|
153
152
|
</svg>`
|
|
154
153
|
});
|
|
155
154
|
|
|
156
|
-
|
|
155
|
+
const mistralVibeIcon = new LabIcon({
|
|
157
156
|
name: 'xtralab:agent-mistral-vibe',
|
|
158
157
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="none">
|
|
159
158
|
<g transform="translate(48 71) scale(0.84)">
|
|
@@ -171,7 +170,7 @@ export const mistralVibeIcon = new LabIcon({
|
|
|
171
170
|
</svg>`
|
|
172
171
|
});
|
|
173
172
|
|
|
174
|
-
|
|
173
|
+
const opencodeIcon = new LabIcon({
|
|
175
174
|
name: 'xtralab:agent-opencode',
|
|
176
175
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
|
|
177
176
|
<rect width="512" height="512" fill="#131010"/>
|
|
@@ -180,14 +179,14 @@ export const opencodeIcon = new LabIcon({
|
|
|
180
179
|
</svg>`
|
|
181
180
|
});
|
|
182
181
|
|
|
183
|
-
|
|
182
|
+
const neovimIcon = new LabIcon({
|
|
184
183
|
name: 'xtralab:editor-neovim',
|
|
185
184
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#57A143">
|
|
186
185
|
<path d="M2.214 4.954v13.615L7.655 24V10.314L3.312 3.845 2.214 4.954zm4.999 17.98l-4.557-4.548V5.136l.59-.596 3.967 5.908v12.485zm14.573-4.457l-.862.937-4.24-6.376V0l5.068 5.092.034 13.385zM7.431.001l12.998 19.835-3.637 3.637L3.787 3.683 7.43 0z"/>
|
|
187
186
|
</svg>`
|
|
188
187
|
});
|
|
189
188
|
|
|
190
|
-
|
|
189
|
+
const vimIcon = new LabIcon({
|
|
191
190
|
name: 'xtralab:editor-vim',
|
|
192
191
|
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#019733">
|
|
193
192
|
<path d="M24 11.986h-.027l-4.318-4.318 4.303-4.414V1.461l-.649-.648h-8.198l-.66.605v1.045L12.015.027V0L12 .014 11.986 0v.027l-1.29 1.291-.538-.539H2.035l-.638.692v1.885l.616.616h.72v5.31L.027 11.987H0L.014 12 0 12.014h.027l2.706 2.706v6.467l.907.523h2.322l1.857-1.904 4.166 4.166V24l.015-.014.014.014v-.028l2.51-2.509h.485c.111 0 .211-.07.25-.179l.146-.426c.028-.084.012-.172-.037-.239l1.462-1.462-.612 1.962c-.043.141.036.289.177.332.025.008.052.012.078.012h1.824c.106-.001.201-.064.243-.163l.165-.394c.025-.065.024-.138-.004-.203-.027-.065-.08-.116-.146-.142-.029-.012-.062-.019-.097-.02h-.075l.84-2.644h1.232l-1.016 3.221c-.043.141.036.289.176.332.025.008.052.012.079.012h2.002c.11 0 .207-.066.248-.17l.164-.428c.051-.138-.021-.29-.158-.341-.029-.011-.06-.017-.091-.017h-.145l1.131-3.673c.027-.082.012-.173-.039-.24l-.375-.504-.003-.005c-.051-.064-.127-.102-.209-.102h-1.436c-.071 0-.141.03-.19.081l-.4.439h-.624l-.042-.046 4.445-4.445H24L23.986 12l.014-.014zM9.838 21.139l1.579-4.509h-.501l.297-.304h1.659l-1.563 4.555h.623l-.079.258H9.838zm3.695-7.516l.15.151-.269.922-.225.226h-.969l-.181-.181.311-.871.288-.247h.895zM5.59 20.829H3.877l-.262-.15V3.091H2.379l-.1-.1V1.815l.143-.154h7.371l.213.214v1.108l-.142.173H8.785v8.688l8.807-8.688h-2.086l-.175-.188V1.805l.121-.111h7.49l.132.133v1.07L12.979 13.25h-.373c-.015-.001-.028 0-.042.001l-.02.003c-.045.01-.086.03-.119.06l-.343.295-.004.003c-.033.031-.059.069-.073.111l-.296.83-6.119 6.276zm14.768-3.952l.474-.519h1.334l.309.415-1.265 4.107h.493l-.08.209H19.84l1.124-3.564h-2.015l-1.077 3.391h.424l-.073.174h-1.605l1.107-3.548h-2.096l-1.062 3.339h.436l-.072.209H13.27l1.514-4.46H14.198l.091-.271h1.65l.519.537h.906l.491-.554h1.061l.489.535h.953z"/>
|
package/src/launcher/index.ts
CHANGED
|
@@ -164,7 +164,8 @@ const plugin: JupyterFrontEndPlugin<IAgentRegistry> = {
|
|
|
164
164
|
// the git panel and the stock launcher: let the server resolve
|
|
165
165
|
// the working tree from its root directory.
|
|
166
166
|
repoPath: '',
|
|
167
|
-
cwd: ''
|
|
167
|
+
cwd: '',
|
|
168
|
+
trans
|
|
168
169
|
});
|
|
169
170
|
launcher.title.icon = launcherIcon;
|
|
170
171
|
launcher.title.label = trans.__('Launcher');
|
|
@@ -14,7 +14,7 @@ import type { IAgent } from './agents';
|
|
|
14
14
|
* longer involved. Backslashes and single quotes are escaped first so
|
|
15
15
|
* the source text round-trips unchanged.
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
function shellQuote(value: string): string {
|
|
18
18
|
const escaped = value
|
|
19
19
|
.replace(/\\/g, '\\\\')
|
|
20
20
|
.replace(/'/g, "\\'")
|
|
@@ -4,7 +4,9 @@ import type { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
|
4
4
|
import { defaultAgentSettings } from './agents';
|
|
5
5
|
import { defaultEditorSettings } from './editors';
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Schema id the launcher's `agents`/`editors` settings live under.
|
|
9
|
+
*/
|
|
8
10
|
export const LAUNCHER_PLUGIN_ID = 'xtralab:launcher';
|
|
9
11
|
|
|
10
12
|
/**
|
package/src/mimeData.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReadonlyPartialJSONValue } from '@lumino/coreutils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parse a JSON-typed value that may have arrived as a string. Agents and the
|
|
5
|
+
* MCP bridge sometimes serialize a spec (e.g. a Vega-Lite object) to a string;
|
|
6
|
+
* for `application/...json` MIME types we accept either and parse the string.
|
|
7
|
+
*/
|
|
8
|
+
export function coerceData(
|
|
9
|
+
mimeType: string,
|
|
10
|
+
data: ReadonlyPartialJSONValue
|
|
11
|
+
): ReadonlyPartialJSONValue {
|
|
12
|
+
if (typeof data === 'string' && /\+?json$/.test(mimeType)) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(data) as ReadonlyPartialJSONValue;
|
|
15
|
+
} catch {
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return data;
|
|
20
|
+
}
|
package/src/omnibox/index.ts
CHANGED
|
@@ -3,11 +3,14 @@ import {
|
|
|
3
3
|
JupyterFrontEndPlugin
|
|
4
4
|
} from '@jupyterlab/application';
|
|
5
5
|
import { ICommandPalette } from '@jupyterlab/apputils';
|
|
6
|
+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
7
|
+
import { IStateDB } from '@jupyterlab/statedb';
|
|
6
8
|
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
7
9
|
import { Widget } from '@lumino/widgets';
|
|
8
10
|
|
|
9
11
|
import { IAgentRegistry } from '../launcher/tokens';
|
|
10
12
|
|
|
13
|
+
import { OmniboxRecents } from './recents';
|
|
11
14
|
import { IOmnibox, OMNIBOX_OPEN_COMMAND } from './tokens';
|
|
12
15
|
import { OmniboxWidget } from './widget';
|
|
13
16
|
|
|
@@ -20,6 +23,10 @@ const PLUGIN_ID = 'xtralab:omnibox';
|
|
|
20
23
|
* it in a fresh terminal through the launcher's `xtralab:start-agent:<id>`
|
|
21
24
|
* commands). It is opened by the top-bar command bar.
|
|
22
25
|
*
|
|
26
|
+
* Commands run and files opened through the overlay are remembered (persisted
|
|
27
|
+
* in the state database) and offered again at the top while the query is
|
|
28
|
+
* empty; the `maxNumberRecents` setting caps how many of each are kept.
|
|
29
|
+
*
|
|
23
30
|
* The agent rows come from the launcher's `IAgentRegistry`; when the launcher
|
|
24
31
|
* is disabled the omnibox still searches files and commands.
|
|
25
32
|
*/
|
|
@@ -29,17 +36,56 @@ const plugin: JupyterFrontEndPlugin<IOmnibox> = {
|
|
|
29
36
|
'A launcher overlay that searches files and commands and prompts agents.',
|
|
30
37
|
autoStart: true,
|
|
31
38
|
provides: IOmnibox,
|
|
32
|
-
optional: [
|
|
39
|
+
optional: [
|
|
40
|
+
IAgentRegistry,
|
|
41
|
+
ICommandPalette,
|
|
42
|
+
ISettingRegistry,
|
|
43
|
+
IStateDB,
|
|
44
|
+
ITranslator
|
|
45
|
+
],
|
|
33
46
|
activate: (
|
|
34
47
|
app: JupyterFrontEnd,
|
|
35
48
|
agentRegistry: IAgentRegistry | null,
|
|
36
49
|
palette: ICommandPalette | null,
|
|
50
|
+
settingRegistry: ISettingRegistry | null,
|
|
51
|
+
state: IStateDB | null,
|
|
37
52
|
translator: ITranslator | null
|
|
38
53
|
): IOmnibox => {
|
|
39
54
|
const { commands, docRegistry } = app;
|
|
40
55
|
const trans = (translator ?? nullTranslator).load('jupyterlab');
|
|
41
56
|
const placeholder = trans.__('Search files and commands, or ask an agent…');
|
|
42
57
|
|
|
58
|
+
const recents = new OmniboxRecents({ state });
|
|
59
|
+
|
|
60
|
+
// Restore the persisted recents only after the configured cap is known:
|
|
61
|
+
// `restore` trims to `maxItems`, so restoring at the constructor default
|
|
62
|
+
// would permanently drop entries beyond it whenever the user configured a
|
|
63
|
+
// larger cap and the state fetch won the race against the settings load.
|
|
64
|
+
if (settingRegistry) {
|
|
65
|
+
void settingRegistry
|
|
66
|
+
.load(PLUGIN_ID)
|
|
67
|
+
.then(settings => {
|
|
68
|
+
const apply = (): void => {
|
|
69
|
+
const value = settings.get('maxNumberRecents').composite;
|
|
70
|
+
if (typeof value === 'number') {
|
|
71
|
+
recents.maxItems = value;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
apply();
|
|
75
|
+
settings.changed.connect(apply);
|
|
76
|
+
void recents.restore();
|
|
77
|
+
})
|
|
78
|
+
.catch(reason => {
|
|
79
|
+
console.error(
|
|
80
|
+
`xtralab omnibox: failed to load settings for ${PLUGIN_ID}`,
|
|
81
|
+
reason
|
|
82
|
+
);
|
|
83
|
+
void recents.restore();
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
void recents.restore();
|
|
87
|
+
}
|
|
88
|
+
|
|
43
89
|
let current: OmniboxWidget | null = null;
|
|
44
90
|
|
|
45
91
|
const close = (): void => {
|
|
@@ -58,6 +104,7 @@ const plugin: JupyterFrontEndPlugin<IOmnibox> = {
|
|
|
58
104
|
agents: agentRegistry ? agentRegistry.agents : [],
|
|
59
105
|
placeholder,
|
|
60
106
|
initialQuery: query ?? '',
|
|
107
|
+
recents,
|
|
61
108
|
trans,
|
|
62
109
|
onClose: close
|
|
63
110
|
});
|