xtralab 0.4.0 → 0.6.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/README.md +110 -73
- package/lib/agentSessions.d.ts +50 -0
- package/lib/agentSessions.js +45 -0
- package/lib/fileBrowser/index.js +5 -1
- package/lib/git/commands.d.ts +12 -13
- package/lib/git/commands.js +7 -28
- package/lib/git/diffProvider.d.ts +8 -0
- package/lib/git/diffProvider.js +314 -0
- package/lib/git/diffSurface.d.ts +115 -0
- package/lib/git/diffSurface.js +342 -0
- package/lib/git/diffWidget.d.ts +8 -13
- package/lib/git/diffWidget.js +65 -311
- package/lib/git/imageDiff.d.ts +23 -0
- package/lib/git/imageDiff.js +256 -0
- package/lib/git/index.d.ts +10 -8
- package/lib/git/index.js +37 -52
- package/lib/index.d.ts +4 -2
- package/lib/index.js +14 -8
- package/lib/launcher/agents.d.ts +1 -1
- package/lib/launcher/agents.js +22 -13
- package/lib/launcher/commands.d.ts +32 -6
- package/lib/launcher/commands.js +81 -57
- package/lib/launcher/dashboard.d.ts +15 -0
- package/lib/launcher/dashboard.js +119 -5
- package/lib/launcher/editorRegistry.d.ts +43 -0
- package/lib/launcher/editorRegistry.js +96 -0
- package/lib/launcher/editors.d.ts +78 -0
- package/lib/launcher/editors.js +110 -0
- package/lib/launcher/icons.d.ts +25 -6
- package/lib/launcher/icons.js +116 -19
- package/lib/launcher/index.d.ts +2 -22
- package/lib/launcher/index.js +48 -25
- package/lib/launcher/registry.d.ts +21 -0
- package/lib/launcher/registry.js +28 -0
- package/lib/launcher/tokens.d.ts +41 -0
- package/lib/launcher/tokens.js +17 -0
- package/lib/terminals/detection.d.ts +11 -0
- package/lib/terminals/detection.js +50 -0
- package/lib/terminals/index.d.ts +27 -0
- package/lib/terminals/index.js +194 -0
- package/lib/terminals/model.d.ts +191 -0
- package/lib/terminals/model.js +418 -0
- package/lib/terminals/widget.d.ts +72 -0
- package/lib/terminals/widget.js +93 -0
- package/lib/topBar/icons.d.ts +13 -0
- package/lib/topBar/icons.js +27 -0
- package/lib/topBar/index.d.ts +16 -0
- package/lib/topBar/index.js +86 -0
- package/package.json +52 -35
- package/schema/launcher.json +56 -1
- package/src/agentSessions.ts +94 -0
- package/src/fileBrowser/index.ts +5 -1
- package/src/git/commands.ts +12 -38
- package/src/git/diffProvider.tsx +462 -0
- package/src/git/diffSurface.tsx +588 -0
- package/src/git/diffWidget.tsx +105 -465
- package/src/git/imageDiff.tsx +469 -0
- package/src/git/index.ts +38 -68
- package/src/index.ts +14 -8
- package/src/launcher/agents.ts +23 -14
- package/src/launcher/commands.ts +98 -60
- package/src/launcher/dashboard.tsx +205 -3
- package/src/launcher/editorRegistry.ts +149 -0
- package/src/launcher/editors.ts +183 -0
- package/src/launcher/icons.ts +120 -20
- package/src/launcher/index.ts +62 -27
- package/src/launcher/registry.ts +33 -0
- package/src/launcher/tokens.ts +51 -0
- package/src/terminals/detection.ts +65 -0
- package/src/terminals/index.ts +222 -0
- package/src/terminals/model.ts +497 -0
- package/src/terminals/widget.tsx +240 -0
- package/src/topBar/icons.ts +30 -0
- package/src/topBar/index.ts +121 -0
- package/style/git.css +267 -266
- package/style/index.css +2 -1
- package/style/index.js +2 -1
- package/style/launcher.css +124 -2
- package/style/terminals.css +235 -0
- package/style/topBar.css +38 -0
- package/lib/git/icons.d.ts +0 -14
- package/lib/git/icons.js +0 -19
- package/lib/git/panel.d.ts +0 -29
- package/lib/git/panel.js +0 -42
- package/lib/git/panelComponent.d.ts +0 -28
- package/lib/git/panelComponent.js +0 -320
- package/lib/statusBar/index.d.ts +0 -14
- package/lib/statusBar/index.js +0 -89
- package/lib/statusBar/widget.d.ts +0 -121
- package/lib/statusBar/widget.js +0 -237
- package/src/git/icons.ts +0 -20
- package/src/git/panel.tsx +0 -56
- package/src/git/panelComponent.tsx +0 -575
- package/src/statusBar/index.ts +0 -115
- package/src/statusBar/widget.tsx +0 -318
- package/style/statusBar.css +0 -95
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ILabShell } from '@jupyterlab/application';
|
|
2
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
3
|
+
import { CommandToolbarButton } from '@jupyterlab/ui-components';
|
|
4
|
+
import { leftSidebarIcon, rightSidebarIcon } from './icons';
|
|
5
|
+
const PLUGIN_ID = 'xtralab:top-bar';
|
|
6
|
+
/**
|
|
7
|
+
* Upstream commands from `@jupyterlab/application-extension` that collapse or
|
|
8
|
+
* expand the side areas. We bind the buttons to these rather than
|
|
9
|
+
* reimplementing the toggle, so behavior (and the `isToggled`/`isEnabled`
|
|
10
|
+
* state the buttons reflect) stays in lockstep with the View menu entries
|
|
11
|
+
* and their keyboard shortcuts.
|
|
12
|
+
*/
|
|
13
|
+
const TOGGLE_LEFT_AREA = 'application:toggle-left-area';
|
|
14
|
+
const TOGGLE_RIGHT_AREA = 'application:toggle-right-area';
|
|
15
|
+
const BUTTONS = [
|
|
16
|
+
{
|
|
17
|
+
id: 'xtralab-toggle-left-sidebar',
|
|
18
|
+
command: TOGGLE_LEFT_AREA,
|
|
19
|
+
icon: leftSidebarIcon,
|
|
20
|
+
caption: trans => trans.__('Toggle left sidebar'),
|
|
21
|
+
rank: -1,
|
|
22
|
+
sideClass: 'xtralab-TopBarButton-left'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'xtralab-toggle-right-sidebar',
|
|
26
|
+
command: TOGGLE_RIGHT_AREA,
|
|
27
|
+
icon: rightSidebarIcon,
|
|
28
|
+
caption: trans => trans.__('Toggle right sidebar'),
|
|
29
|
+
rank: 1000,
|
|
30
|
+
sideClass: 'xtralab-TopBarButton-right'
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Add two icon buttons to the top bar that toggle the left and right side
|
|
35
|
+
* areas, mirroring the macOS-style sidebar buttons: a left-sidebar button at
|
|
36
|
+
* the leading edge and a right-sidebar button at the far edge.
|
|
37
|
+
*
|
|
38
|
+
* Each is a `CommandToolbarButton` wrapping an existing
|
|
39
|
+
* `application:toggle-{left,right}-area` command, so clicking it runs the
|
|
40
|
+
* same toggle as the View menu and the button reflects the command's state —
|
|
41
|
+
* pressed while the matching sidebar is open, and disabled when the area is
|
|
42
|
+
* empty. Note xtralab ships nothing in the right area by default (the
|
|
43
|
+
* property inspector, table of contents and debugger are all disabled), so
|
|
44
|
+
* the right button stays disabled until a widget is moved or added there.
|
|
45
|
+
*/
|
|
46
|
+
const plugin = {
|
|
47
|
+
id: PLUGIN_ID,
|
|
48
|
+
description: 'Add left and right sidebar toggle buttons to the top bar.',
|
|
49
|
+
autoStart: true,
|
|
50
|
+
requires: [ILabShell],
|
|
51
|
+
optional: [ITranslator],
|
|
52
|
+
activate: (app, labShell, translator) => {
|
|
53
|
+
const { commands } = app;
|
|
54
|
+
const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
|
|
55
|
+
// Defer to `app.restored` so the upstream toggle commands are already in
|
|
56
|
+
// the registry: `CommandToolbarButton` renders nothing until its command
|
|
57
|
+
// exists and only re-renders on `commandChanged` of type `changed` /
|
|
58
|
+
// `many-changed` (not `added`), so mounting earlier could leave a button
|
|
59
|
+
// blank until the next unrelated command change.
|
|
60
|
+
void app.restored.then(() => {
|
|
61
|
+
for (const spec of BUTTONS) {
|
|
62
|
+
const button = new CommandToolbarButton({
|
|
63
|
+
commands,
|
|
64
|
+
id: spec.command,
|
|
65
|
+
icon: spec.icon,
|
|
66
|
+
// Empty label keeps the button icon-only: the override is forwarded
|
|
67
|
+
// verbatim and the component skips the label span when it is falsy.
|
|
68
|
+
label: '',
|
|
69
|
+
caption: spec.caption(trans),
|
|
70
|
+
// Toggle on mousedown without focusing the button. Otherwise
|
|
71
|
+
// ToolbarButtonComponent calls `event.target.focus()` on click,
|
|
72
|
+
// leaving the stealth button showing a focus fill/outline (the
|
|
73
|
+
// stray "border") until you click elsewhere — unwanted chrome for a
|
|
74
|
+
// title-bar control. Keyboard Tab focus still works, so this stays
|
|
75
|
+
// accessible.
|
|
76
|
+
noFocusOnClick: true
|
|
77
|
+
});
|
|
78
|
+
button.id = spec.id;
|
|
79
|
+
button.addClass('xtralab-TopBarButton');
|
|
80
|
+
button.addClass(spec.sideClass);
|
|
81
|
+
labShell.add(button, 'top', { rank: spec.rank });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
export default plugin;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xtralab",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "An opinionated JupyterLab meta-package that bundles a curated set of extensions, ships a path-first file browser and
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "An opinionated JupyterLab meta-package that bundles a curated set of extensions, ships a path-first file browser, renders jupyterlab-git's text, notebook and image diffs with its own viewers, and applies a quieter default workspace configuration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
7
7
|
"jupyterlab",
|
|
@@ -30,27 +30,28 @@
|
|
|
30
30
|
"type": "git",
|
|
31
31
|
"url": "https://github.com/jtpio/xtralab.git"
|
|
32
32
|
},
|
|
33
|
+
"packageManager": "pnpm@10.28.0",
|
|
33
34
|
"scripts": {
|
|
34
|
-
"build": "
|
|
35
|
-
"build:prod": "
|
|
35
|
+
"build": "pnpm build:lib && pnpm build:labextension:dev",
|
|
36
|
+
"build:prod": "pnpm clean && pnpm build:lib:prod && pnpm build:labextension",
|
|
36
37
|
"build:labextension": "jupyter-builder build .",
|
|
37
38
|
"build:labextension:dev": "jupyter-builder build --development True .",
|
|
38
39
|
"build:lib": "tsc --sourceMap",
|
|
39
40
|
"build:lib:prod": "tsc",
|
|
40
|
-
"clean": "
|
|
41
|
+
"clean": "pnpm clean:lib",
|
|
41
42
|
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
42
43
|
"clean:lintcache": "rimraf .eslintcache .stylelintcache",
|
|
43
44
|
"clean:labextension": "rimraf xtralab/labextension xtralab/_version.py",
|
|
44
|
-
"clean:all": "
|
|
45
|
-
"eslint": "
|
|
45
|
+
"clean:all": "pnpm clean:lib && pnpm clean:labextension && pnpm clean:lintcache",
|
|
46
|
+
"eslint": "pnpm eslint:check --fix",
|
|
46
47
|
"eslint:check": "eslint . --cache --ext .ts,.tsx",
|
|
47
|
-
"install:extension": "
|
|
48
|
-
"lint": "
|
|
49
|
-
"lint:check": "
|
|
50
|
-
"prettier": "
|
|
48
|
+
"install:extension": "pnpm build",
|
|
49
|
+
"lint": "pnpm stylelint && pnpm prettier && pnpm eslint",
|
|
50
|
+
"lint:check": "pnpm stylelint:check && pnpm prettier:check && pnpm eslint:check",
|
|
51
|
+
"prettier": "pnpm prettier:base --write --list-different",
|
|
51
52
|
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
|
52
|
-
"prettier:check": "
|
|
53
|
-
"stylelint": "
|
|
53
|
+
"prettier:check": "pnpm prettier:base --check",
|
|
54
|
+
"stylelint": "pnpm stylelint:check --fix",
|
|
54
55
|
"stylelint:check": "stylelint --cache \"style/**/*.css\"",
|
|
55
56
|
"watch": "run-p watch:src watch:labextension",
|
|
56
57
|
"watch:src": "tsc -w --sourceMap",
|
|
@@ -60,24 +61,25 @@
|
|
|
60
61
|
"@codemirror/language": "^6.12.1",
|
|
61
62
|
"@codemirror/state": "^6.5.4",
|
|
62
63
|
"@codemirror/view": "^6.39.14",
|
|
63
|
-
"@jupyterlab/application": "^4.6.0-
|
|
64
|
-
"@jupyterlab/apputils": "^4.7.0-
|
|
65
|
-
"@jupyterlab/codemirror": "^4.6.0-
|
|
66
|
-
"@jupyterlab/coreutils": "^6.6.0-
|
|
67
|
-
"@jupyterlab/docmanager": "^4.6.0-
|
|
68
|
-
"@jupyterlab/docregistry": "^4.6.0-
|
|
69
|
-
"@jupyterlab/
|
|
70
|
-
"@jupyterlab/
|
|
71
|
-
"@jupyterlab/
|
|
72
|
-
"@jupyterlab/
|
|
73
|
-
"@jupyterlab/
|
|
74
|
-
"@jupyterlab/
|
|
75
|
-
"@jupyterlab/
|
|
76
|
-
"@jupyterlab/
|
|
77
|
-
"@jupyterlab/terminal": "^4.6.0-
|
|
78
|
-
"@jupyterlab/translation": "^4.6.0-
|
|
79
|
-
"@jupyterlab/ui-components": "^4.6.0-
|
|
64
|
+
"@jupyterlab/application": "^4.6.0-beta.0",
|
|
65
|
+
"@jupyterlab/apputils": "^4.7.0-beta.0",
|
|
66
|
+
"@jupyterlab/codemirror": "^4.6.0-beta.0",
|
|
67
|
+
"@jupyterlab/coreutils": "^6.6.0-beta.0",
|
|
68
|
+
"@jupyterlab/docmanager": "^4.6.0-beta.0",
|
|
69
|
+
"@jupyterlab/docregistry": "^4.6.0-beta.0",
|
|
70
|
+
"@jupyterlab/git": "^0.54.0-a1",
|
|
71
|
+
"@jupyterlab/launcher": "^4.6.0-beta.0",
|
|
72
|
+
"@jupyterlab/mainmenu": "^4.6.0-beta.0",
|
|
73
|
+
"@jupyterlab/nbformat": "^4.6.0-beta.0",
|
|
74
|
+
"@jupyterlab/outputarea": "^4.6.0-beta.0",
|
|
75
|
+
"@jupyterlab/rendermime": "^4.6.0-beta.0",
|
|
76
|
+
"@jupyterlab/services": "^7.6.0-beta.0",
|
|
77
|
+
"@jupyterlab/settingregistry": "^4.6.0-beta.0",
|
|
78
|
+
"@jupyterlab/terminal": "^4.6.0-beta.0",
|
|
79
|
+
"@jupyterlab/translation": "^4.6.0-beta.0",
|
|
80
|
+
"@jupyterlab/ui-components": "^4.6.0-beta.0",
|
|
80
81
|
"@lumino/algorithm": "^2.0.0",
|
|
82
|
+
"@lumino/commands": "^2.0.0",
|
|
81
83
|
"@lumino/coreutils": "^2.0.0",
|
|
82
84
|
"@lumino/disposable": "^2.0.0",
|
|
83
85
|
"@lumino/dragdrop": "^2.0.0",
|
|
@@ -93,7 +95,7 @@
|
|
|
93
95
|
"react-dom": "^18.2.0"
|
|
94
96
|
},
|
|
95
97
|
"devDependencies": {
|
|
96
|
-
"@jupyter/builder": "^0.0.
|
|
98
|
+
"@jupyter/builder": "^1.0.0-beta.1",
|
|
97
99
|
"@types/json-schema": "^7.0.11",
|
|
98
100
|
"@types/react": "^18.0.26",
|
|
99
101
|
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
@@ -116,8 +118,10 @@
|
|
|
116
118
|
"typescript": "~5.5.4",
|
|
117
119
|
"yjs": "^13.5.0"
|
|
118
120
|
},
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
+
"pnpm": {
|
|
122
|
+
"ignoredBuiltDependencies": [
|
|
123
|
+
"@fortawesome/fontawesome-free"
|
|
124
|
+
]
|
|
121
125
|
},
|
|
122
126
|
"sideEffects": [
|
|
123
127
|
"style/*.css",
|
|
@@ -131,8 +135,16 @@
|
|
|
131
135
|
"extension": true,
|
|
132
136
|
"outputDir": "xtralab/labextension",
|
|
133
137
|
"schemaDir": "schema",
|
|
138
|
+
"sharedPackages": {
|
|
139
|
+
"@jupyterlab/git": {
|
|
140
|
+
"bundled": false,
|
|
141
|
+
"singleton": true
|
|
142
|
+
}
|
|
143
|
+
},
|
|
134
144
|
"disabledExtensions": [
|
|
135
|
-
"@jupyterlab/git",
|
|
145
|
+
"@jupyterlab/git:notebook-diff",
|
|
146
|
+
"@jupyterlab/git:plain-text-diff",
|
|
147
|
+
"@jupyterlab/git:image-diff",
|
|
136
148
|
"@jupyterlab/launcher-extension"
|
|
137
149
|
]
|
|
138
150
|
},
|
|
@@ -140,7 +152,12 @@
|
|
|
140
152
|
"node_modules",
|
|
141
153
|
"dist",
|
|
142
154
|
"coverage",
|
|
143
|
-
"**/*.d.ts"
|
|
155
|
+
"**/*.d.ts",
|
|
156
|
+
"desktop/out",
|
|
157
|
+
"desktop/dist",
|
|
158
|
+
"desktop/python/wheels",
|
|
159
|
+
"desktop/python/runtime",
|
|
160
|
+
"desktop/python/runtime.staging"
|
|
144
161
|
],
|
|
145
162
|
"eslintConfig": {
|
|
146
163
|
"extends": [
|
package/schema/launcher.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"properties": {
|
|
8
8
|
"agents": {
|
|
9
9
|
"title": "Agents",
|
|
10
|
-
"description": "Override or extend the built-in list of agents shown on the launcher. Each entry must include an `id`. When the id matches a built-in (claude, codex,
|
|
10
|
+
"description": "Override or extend the built-in list of agents shown on the launcher. Each entry must include an `id`. When the id matches a built-in (claude, codex, antigravity, copilot, goose, opencode, kiro, mistral-vibe), the fields you set override the corresponding defaults; leave a field out to keep the default. New ids define brand-new cards. Set `enabled: false` to hide a default. Set `requireAvailable: false` for shell aliases that should always show even though they aren't on PATH.",
|
|
11
11
|
"type": "array",
|
|
12
12
|
"default": [],
|
|
13
13
|
"items": {
|
|
@@ -65,6 +65,61 @@
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
},
|
|
69
|
+
"editors": {
|
|
70
|
+
"title": "Editors",
|
|
71
|
+
"description": "Override or extend the terminal editors offered in the launcher's Open section (and recognized in the Terminals panel). Each entry must include an `id`. When the id matches a built-in (nvim, vim), the fields you set override the corresponding defaults; leave a field out to keep the default. New ids define additional editors. The launcher shows a single tile — the first editor, by `rank`, whose `command` is on PATH (Neovim before Vim by default). Set `enabled: false` to hide a built-in; disable both to remove the tile entirely. Set `requireAvailable: false` for a shell alias that should show even though it isn't on PATH.",
|
|
72
|
+
"type": "array",
|
|
73
|
+
"default": [],
|
|
74
|
+
"items": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"required": ["id"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"id": {
|
|
80
|
+
"title": "ID",
|
|
81
|
+
"description": "Stable identifier. Match a built-in (nvim, vim) to override, or pick a new id to define a new editor.",
|
|
82
|
+
"type": "string"
|
|
83
|
+
},
|
|
84
|
+
"label": {
|
|
85
|
+
"title": "Label",
|
|
86
|
+
"description": "Tile title shown on the launcher.",
|
|
87
|
+
"type": "string"
|
|
88
|
+
},
|
|
89
|
+
"caption": {
|
|
90
|
+
"title": "Caption",
|
|
91
|
+
"description": "Tooltip shown for the tile.",
|
|
92
|
+
"type": "string"
|
|
93
|
+
},
|
|
94
|
+
"command": {
|
|
95
|
+
"title": "Command",
|
|
96
|
+
"description": "Literal string typed into the new terminal (e.g. `nvim`). Aliases work because shells expand them on interactive lines.",
|
|
97
|
+
"type": "string"
|
|
98
|
+
},
|
|
99
|
+
"iconSvg": {
|
|
100
|
+
"title": "Icon SVG",
|
|
101
|
+
"description": "Inline SVG for the tile icon. Required only for new editors whose icon is not already shipped by xtralab.",
|
|
102
|
+
"type": "string"
|
|
103
|
+
},
|
|
104
|
+
"rank": {
|
|
105
|
+
"title": "Rank",
|
|
106
|
+
"description": "Preference order (lower numbers come first). The launcher shows the first available editor by rank.",
|
|
107
|
+
"type": "number"
|
|
108
|
+
},
|
|
109
|
+
"enabled": {
|
|
110
|
+
"title": "Enabled",
|
|
111
|
+
"description": "When false, hides the editor from the launcher (and the Terminals panel stops badging it).",
|
|
112
|
+
"type": "boolean",
|
|
113
|
+
"default": true
|
|
114
|
+
},
|
|
115
|
+
"requireAvailable": {
|
|
116
|
+
"title": "Require available",
|
|
117
|
+
"description": "When false, the launcher skips the availability check for this entry (useful for a shell alias that isn't on PATH but resolves in an interactive shell).",
|
|
118
|
+
"type": "boolean",
|
|
119
|
+
"default": true
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
68
123
|
}
|
|
69
124
|
}
|
|
70
125
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
2
|
+
import { Token } from '@lumino/coreutils';
|
|
3
|
+
import { ISignal, Signal } from '@lumino/signaling';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A shared map from a terminal session name to the agent command it was
|
|
7
|
+
* *launched* with (e.g. `claude`).
|
|
8
|
+
*
|
|
9
|
+
* This is the optimistic half of the running-agent badge: when the launcher
|
|
10
|
+
* (or the terminals panel's `+` menu) starts an agent via a
|
|
11
|
+
* `xtralab:start-agent:<id>` command, it records the session here so the
|
|
12
|
+
* panel can show the agent's logo immediately, before the server-side
|
|
13
|
+
* process detection has had a chance to confirm it. Server detection is the
|
|
14
|
+
* authoritative source once it reports on a session; this tag only fills the
|
|
15
|
+
* gap right after launch (and serves as a fallback if detection is
|
|
16
|
+
* unavailable).
|
|
17
|
+
*
|
|
18
|
+
* It exists as its own token, provided by a tiny dependency-free plugin,
|
|
19
|
+
* specifically so the launcher (the writer) and the terminals panel (the
|
|
20
|
+
* reader) can share it without depending on each other — a direct
|
|
21
|
+
* launcher↔terminals token pair would form an activation cycle.
|
|
22
|
+
*/
|
|
23
|
+
export interface IAgentSessions {
|
|
24
|
+
/**
|
|
25
|
+
* The agent command a session was launched with, or `null` if we never
|
|
26
|
+
* launched an agent into it (e.g. a plain terminal, or one started before
|
|
27
|
+
* this ran).
|
|
28
|
+
*/
|
|
29
|
+
get(sessionName: string): string | null;
|
|
30
|
+
|
|
31
|
+
/** Record that a session was launched as the given agent command. */
|
|
32
|
+
set(sessionName: string, command: string): void;
|
|
33
|
+
|
|
34
|
+
/** Forget a session — called when it shuts down so the map stays bounded. */
|
|
35
|
+
delete(sessionName: string): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Emitted with the affected session name whenever a record is added or
|
|
39
|
+
* removed, so readers can re-render.
|
|
40
|
+
*/
|
|
41
|
+
readonly changed: ISignal<IAgentSessions, string>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* DI token for {@link IAgentSessions}. Provided by `xtralab:agent-sessions`;
|
|
46
|
+
* consumed (optionally) by both `xtralab:launcher` and `xtralab:terminals`.
|
|
47
|
+
*/
|
|
48
|
+
export const IAgentSessions = new Token<IAgentSessions>(
|
|
49
|
+
'xtralab:IAgentSessions',
|
|
50
|
+
'A shared map from terminal session name to the agent command it was launched with.'
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
class AgentSessions implements IAgentSessions {
|
|
54
|
+
get(sessionName: string): string | null {
|
|
55
|
+
return this._byName.get(sessionName) ?? null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
set(sessionName: string, command: string): void {
|
|
59
|
+
if (this._byName.get(sessionName) === command) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this._byName.set(sessionName, command);
|
|
63
|
+
this._changed.emit(sessionName);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
delete(sessionName: string): void {
|
|
67
|
+
if (this._byName.delete(sessionName)) {
|
|
68
|
+
this._changed.emit(sessionName);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get changed(): ISignal<IAgentSessions, string> {
|
|
73
|
+
return this._changed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private _byName = new Map<string, string>();
|
|
77
|
+
private _changed = new Signal<IAgentSessions, string>(this);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Provides {@link IAgentSessions}. Deliberately has no dependencies so it can
|
|
82
|
+
* sit underneath both the launcher and the terminals panel without creating
|
|
83
|
+
* a dependency cycle between them.
|
|
84
|
+
*/
|
|
85
|
+
const plugin: JupyterFrontEndPlugin<IAgentSessions> = {
|
|
86
|
+
id: 'xtralab:agent-sessions',
|
|
87
|
+
description:
|
|
88
|
+
'Shared map from terminal session to the agent command it was launched with, used to badge terminal rows with the running agent.',
|
|
89
|
+
autoStart: true,
|
|
90
|
+
provides: IAgentSessions,
|
|
91
|
+
activate: (): IAgentSessions => new AgentSessions()
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default plugin;
|
package/src/fileBrowser/index.ts
CHANGED
|
@@ -37,7 +37,11 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
37
37
|
void app.commands.execute('docmanager:open', { path: serverPath });
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
|
-
|
|
40
|
+
// Ranks just under the Terminals panel in the left sidebar. The shipped
|
|
41
|
+
// `layout` setting assigns the default ranks (rank only, no area pin),
|
|
42
|
+
// so this browser stays movable via the "Move Widget" context menu; the
|
|
43
|
+
// `rank` here is the in-code fallback for when that setting is absent.
|
|
44
|
+
app.shell.add(browser, 'left', { rank: 2 });
|
|
41
45
|
if (restorer) {
|
|
42
46
|
restorer.add(browser, browser.id);
|
|
43
47
|
}
|
package/src/git/commands.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { JupyterFrontEnd } from '@jupyterlab/application';
|
|
2
|
-
import {
|
|
2
|
+
import { IThemeManager } from '@jupyterlab/apputils';
|
|
3
3
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
4
4
|
import { Contents } from '@jupyterlab/services';
|
|
5
|
-
import { refreshIcon } from '@jupyterlab/ui-components';
|
|
6
5
|
import { ReadonlyPartialJSONObject } from '@lumino/coreutils';
|
|
7
6
|
|
|
8
7
|
import {
|
|
@@ -10,16 +9,15 @@ import {
|
|
|
10
9
|
diffWidgetId,
|
|
11
10
|
updateGitDiffWidget
|
|
12
11
|
} from './diffWidget';
|
|
13
|
-
import { GitPanel } from './panel';
|
|
14
12
|
import { IFileChange } from './tokens';
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
|
-
* Command IDs exposed by the git
|
|
18
|
-
* {@link
|
|
19
|
-
*
|
|
15
|
+
* Command IDs exposed by the launcher's git diff path. The launcher
|
|
16
|
+
* dashboard's "Changes" section drives {@link CommandIDs.openDiff} to open
|
|
17
|
+
* its own diff tab, independent of `jupyterlab-git` (whose panel reaches
|
|
18
|
+
* the same rendering via the providers in `diffProvider.tsx`).
|
|
20
19
|
*/
|
|
21
20
|
export namespace CommandIDs {
|
|
22
|
-
export const refresh = 'xtralab:git:refresh';
|
|
23
21
|
export const openDiff = 'xtralab:git:open-diff';
|
|
24
22
|
}
|
|
25
23
|
|
|
@@ -39,9 +37,7 @@ export namespace CommandArguments {
|
|
|
39
37
|
|
|
40
38
|
export interface IRegisterGitCommandsOptions {
|
|
41
39
|
app: JupyterFrontEnd;
|
|
42
|
-
panel: GitPanel;
|
|
43
40
|
themeManager: IThemeManager | null;
|
|
44
|
-
commandPalette: ICommandPalette | null;
|
|
45
41
|
/**
|
|
46
42
|
* Contents manager used by the diff widget to write hunk-discard
|
|
47
43
|
* results back to the working tree.
|
|
@@ -56,7 +52,10 @@ export interface IRegisterGitCommandsOptions {
|
|
|
56
52
|
rendermime: IRenderMimeRegistry | null;
|
|
57
53
|
/**
|
|
58
54
|
* Called whenever the diff widget mutates the working tree (e.g. after
|
|
59
|
-
* a hunk discard)
|
|
55
|
+
* a hunk discard). The launcher dashboard polls git status on its own
|
|
56
|
+
* cadence and `jupyterlab-git`'s panel auto-refreshes on the contents
|
|
57
|
+
* `fileChanged` signal the save emits, so this is a hook for any extra
|
|
58
|
+
* bookkeeping rather than a required refresh.
|
|
60
59
|
*/
|
|
61
60
|
onChanged: () => void;
|
|
62
61
|
/**
|
|
@@ -77,18 +76,15 @@ export interface IRegisterGitCommandsOptions {
|
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
/**
|
|
80
|
-
* Register the git
|
|
81
|
-
*
|
|
82
|
-
* (the commands themselves stay registered for the lifetime of the plugin).
|
|
79
|
+
* Register the launcher's git diff command on the application command
|
|
80
|
+
* registry.
|
|
83
81
|
*/
|
|
84
82
|
export function registerGitCommands(
|
|
85
83
|
options: IRegisterGitCommandsOptions
|
|
86
|
-
):
|
|
84
|
+
): void {
|
|
87
85
|
const {
|
|
88
86
|
app,
|
|
89
|
-
panel,
|
|
90
87
|
themeManager,
|
|
91
|
-
commandPalette,
|
|
92
88
|
contentsManager,
|
|
93
89
|
rendermime,
|
|
94
90
|
onChanged,
|
|
@@ -98,15 +94,6 @@ export function registerGitCommands(
|
|
|
98
94
|
} = options;
|
|
99
95
|
const { commands } = app;
|
|
100
96
|
|
|
101
|
-
commands.addCommand(CommandIDs.refresh, {
|
|
102
|
-
label: 'Refresh Git Changes',
|
|
103
|
-
caption: 'Refresh the git changes panel',
|
|
104
|
-
icon: refreshIcon,
|
|
105
|
-
execute: () => {
|
|
106
|
-
panel.refresh();
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
97
|
commands.addCommand(CommandIDs.openDiff, {
|
|
111
98
|
label: 'Open Git Diff',
|
|
112
99
|
caption: 'Open a side-by-side diff for a changed file',
|
|
@@ -139,19 +126,6 @@ export function registerGitCommands(
|
|
|
139
126
|
app.shell.activateById(widget.id);
|
|
140
127
|
}
|
|
141
128
|
});
|
|
142
|
-
|
|
143
|
-
const paletteItems = commandPalette
|
|
144
|
-
? [
|
|
145
|
-
commandPalette.addItem({
|
|
146
|
-
command: CommandIDs.refresh,
|
|
147
|
-
category: 'Git'
|
|
148
|
-
})
|
|
149
|
-
]
|
|
150
|
-
: [];
|
|
151
|
-
|
|
152
|
-
return () => {
|
|
153
|
-
paletteItems.forEach(item => item.dispose());
|
|
154
|
-
};
|
|
155
129
|
}
|
|
156
130
|
|
|
157
131
|
export { diffWidgetId };
|