jupyterlab_ai_code_assistants_extension 0.6.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +29 -0
- package/README.md +44 -0
- package/lib/core/colour.d.ts +57 -0
- package/lib/core/colour.js +190 -0
- package/lib/core/icons.d.ts +12 -0
- package/lib/core/icons.js +99 -0
- package/lib/core/modes.d.ts +13 -0
- package/lib/core/modes.js +36 -0
- package/lib/core/panel.d.ts +233 -0
- package/lib/core/panel.js +1673 -0
- package/lib/core/popup.d.ts +40 -0
- package/lib/core/popup.js +404 -0
- package/lib/core/registry.d.ts +24 -0
- package/lib/core/registry.js +48 -0
- package/lib/core/request.d.ts +25 -0
- package/lib/core/request.js +64 -0
- package/lib/core/terminals.d.ts +129 -0
- package/lib/core/terminals.js +344 -0
- package/lib/core/types.d.ts +269 -0
- package/lib/core/types.js +6 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +277 -0
- package/lib/providers/claude.d.ts +3 -0
- package/lib/providers/claude.js +88 -0
- package/lib/providers/codex.d.ts +3 -0
- package/lib/providers/codex.js +79 -0
- package/lib/providers/gemini.d.ts +2 -0
- package/lib/providers/gemini.js +73 -0
- package/lib/providers/index.d.ts +3 -0
- package/lib/providers/index.js +16 -0
- package/lib/providers/kimi.d.ts +23 -0
- package/lib/providers/kimi.js +139 -0
- package/package.json +169 -0
- package/schema/plugin.json +93 -0
- package/src/__tests__/colour.spec.ts +153 -0
- package/src/__tests__/core-neutrality.spec.ts +86 -0
- package/src/__tests__/labels.spec.ts +89 -0
- package/src/__tests__/launch-mode.spec.ts +53 -0
- package/src/__tests__/registry.spec.ts +178 -0
- package/src/core/colour.ts +224 -0
- package/src/core/icons.ts +121 -0
- package/src/core/modes.ts +45 -0
- package/src/core/panel.ts +2020 -0
- package/src/core/popup.ts +475 -0
- package/src/core/registry.ts +60 -0
- package/src/core/request.ts +96 -0
- package/src/core/terminals.ts +446 -0
- package/src/core/types.ts +305 -0
- package/src/index.ts +356 -0
- package/src/providers/claude.ts +102 -0
- package/src/providers/codex.ts +89 -0
- package/src/providers/gemini.ts +80 -0
- package/src/providers/index.ts +21 -0
- package/src/providers/kimi.ts +155 -0
- package/style/base.css +888 -0
- package/style/index.css +1 -0
- package/style/index.js +1 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// The Codex provider: OpenAI's `codex` CLI.
|
|
2
|
+
//
|
|
3
|
+
// Ported from `jupyterlab_codex_extension` v0.6.12. Almost everything that
|
|
4
|
+
// extension did by hand is now shared panel behaviour, so what is left here is
|
|
5
|
+
// the descriptor plus the two tooltip lines Codex has and the others do not.
|
|
6
|
+
//
|
|
7
|
+
// The three divergences that matter are capability flags, not code:
|
|
8
|
+
//
|
|
9
|
+
// * `forkStrategy: 'native-command'` - `codex fork <parent>` mints the fork's
|
|
10
|
+
// id itself, so the panel snapshots the branch list, launches, and diffs to
|
|
11
|
+
// discover the id (the shared 2s x 90 discovery watcher)
|
|
12
|
+
// * `colourSource: 'none'` - Codex has no colour concept at all, so a tab tint
|
|
13
|
+
// only ever comes from the extension's own write-back store
|
|
14
|
+
// * `hasLiveProcess: true` - a project row shows a dot when a `codex` process
|
|
15
|
+
// is running in it, which is the only liveness signal Codex exposes
|
|
16
|
+
// The OpenAI "blossom" mark - Codex is OpenAI's CLI, so the panel wears its
|
|
17
|
+
// vendor's logo. Single path, `jp-icon3` so it picks up the theme's foreground
|
|
18
|
+
// in both light and dark. The box stays 16px like every other icon; the mark is
|
|
19
|
+
// scaled down INSIDE it by padding the viewBox (24 units of art in a 30-unit
|
|
20
|
+
// window, so ~80%), which keeps the sidebar tab and header alignment identical
|
|
21
|
+
// while the dense logo reads less heavy than the simpler glyphs around it.
|
|
22
|
+
const codexSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3 -3 30 30" width="16" height="16">
|
|
23
|
+
<path class="jp-icon3" fill="#616161" d="M22.282 9.821a5.985 5.985 0 0 0-.516-4.91 6.046 6.046 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a5.985 5.985 0 0 0-3.998 2.9 6.046 6.046 0 0 0 .743 7.097 5.98 5.98 0 0 0 .51 4.911 6.051 6.051 0 0 0 6.515 2.9A5.985 5.985 0 0 0 13.26 24a6.056 6.056 0 0 0 5.772-4.206 5.99 5.99 0 0 0 3.997-2.9 6.056 6.056 0 0 0-.747-7.073ZM13.26 22.43a4.476 4.476 0 0 1-2.876-1.04l.141-.081 4.779-2.758a.795.795 0 0 0 .392-.681v-6.737l2.02 1.168a.071.071 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494ZM3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085 4.783 2.759a.771.771 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646ZM2.34 7.896a4.485 4.485 0 0 1 2.366-1.973V11.6a.766.766 0 0 0 .388.676l5.815 3.355-2.02 1.168a.076.076 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872Zm16.597 3.858-5.833-3.387L15.119 7.2a.076.076 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667Zm2.01-3.024-.141-.085-4.774-2.782a.776.776 0 0 0-.785 0L9.409 9.23V6.897a.066.066 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66Zm-12.64 4.135-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08L8.704 5.46a.795.795 0 0 0-.393.681ZM9.409 12l2.602-1.504L14.618 12v3.008l-2.597 1.5-2.607-1.5Z"/>
|
|
24
|
+
</svg>`;
|
|
25
|
+
// Codex's own name for its unsafe switch. Kept in the assistant's terminology
|
|
26
|
+
// rather than normalised, because it is both the settings key under
|
|
27
|
+
// `providers.codex.` and the mode token the server maps to the CLI flag
|
|
28
|
+
// `--dangerously-bypass-approvals-and-sandbox`.
|
|
29
|
+
const BYPASS_MODE = 'dangerouslyBypassApprovalsAndSandbox';
|
|
30
|
+
export const descriptor = {
|
|
31
|
+
id: 'codex',
|
|
32
|
+
label: 'Codex',
|
|
33
|
+
panelTitle: 'Codex Sessions',
|
|
34
|
+
iconName: 'jupyterlab_ai_code_assistants_extension:codex',
|
|
35
|
+
iconSvg: codexSvgStr,
|
|
36
|
+
cliBinary: 'codex',
|
|
37
|
+
// `codex fork <parent>` owns both the verb and the new id.
|
|
38
|
+
forkStrategy: 'native-command',
|
|
39
|
+
// No `/color` equivalent, and nothing in the thread store records one.
|
|
40
|
+
colourSource: 'none',
|
|
41
|
+
// Forks are unnamed - Codex has no naming flag and no writable title field,
|
|
42
|
+
// so the panel never asks for a name it could not stamp anywhere.
|
|
43
|
+
namingStrategy: 'none',
|
|
44
|
+
// A bare `codex` mints its own thread id; there is no `--session-id`.
|
|
45
|
+
mintsNewSessionId: false,
|
|
46
|
+
launchModes: [
|
|
47
|
+
{
|
|
48
|
+
id: BYPASS_MODE,
|
|
49
|
+
title: 'Bypass Codex approvals and sandbox',
|
|
50
|
+
description: 'When enabled, newly spawned and resumed sessions are launched with `--dangerously-bypass-approvals-and-sandbox`. Bypasses every Codex approval prompt and sandbox - only enable in environments you trust.',
|
|
51
|
+
kind: 'boolean',
|
|
52
|
+
default: false,
|
|
53
|
+
menuLabel: 'Bypass Approvals'
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
hasRemoteControl: false,
|
|
57
|
+
hasBgAgents: false,
|
|
58
|
+
// A `codex` process running in the project folder is the only liveness
|
|
59
|
+
// signal Codex exposes - it keeps no per-pid session record.
|
|
60
|
+
hasLiveProcess: true,
|
|
61
|
+
// Retired standalone extension this provider replaces.
|
|
62
|
+
legacyPluginId: 'jupyterlab_codex_extension'
|
|
63
|
+
};
|
|
64
|
+
export const hooks = {
|
|
65
|
+
// Codex's thread store records the model and the token spend of every
|
|
66
|
+
// conversation; no other assistant here does, so they are a provider line
|
|
67
|
+
// rather than a core one.
|
|
68
|
+
tooltipLines: ({ session }) => {
|
|
69
|
+
var _a;
|
|
70
|
+
const lines = [];
|
|
71
|
+
if (session.model) {
|
|
72
|
+
lines.push(`Model: ${session.model}`);
|
|
73
|
+
}
|
|
74
|
+
if (((_a = session.tokens_used) !== null && _a !== void 0 ? _a : 0) > 0) {
|
|
75
|
+
lines.push(`Tokens: ${session.tokens_used}`);
|
|
76
|
+
}
|
|
77
|
+
return lines;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// The Gemini provider - Google's `gemini` CLI.
|
|
2
|
+
//
|
|
3
|
+
// New here: no standalone extension preceded it, so there is nothing to port
|
|
4
|
+
// and nothing to migrate. Everything that makes this assistant different from
|
|
5
|
+
// the base one is descriptor data, so no core file knows it exists:
|
|
6
|
+
//
|
|
7
|
+
// * `forkStrategy: 'server-copy'` - gemini has no fork verb at all, so the
|
|
8
|
+
// server copies the chat file under a fresh id and answers with it
|
|
9
|
+
// * `colourSource: 'none'` - no colour command, and nothing in the chat store
|
|
10
|
+
// records one, so a tab tint only ever comes from the extension's own
|
|
11
|
+
// write-back store
|
|
12
|
+
// * `namingStrategy: 'server-side'` - a fork's name is stamped into the copied
|
|
13
|
+
// chat file's `summary`, which is the field the CLI itself displays a
|
|
14
|
+
// conversation under; there is no naming flag to pass it to
|
|
15
|
+
// * `mintsNewSessionId: true` - `--session-id <uuid>` starts a fresh
|
|
16
|
+
// conversation under an id we chose, so a new session is identifiable from
|
|
17
|
+
// its argv on the first poll instead of being an unknown terminal
|
|
18
|
+
// * two launch modes, gemini's `--yolo` switch and its four-step approval
|
|
19
|
+
// ladder
|
|
20
|
+
//
|
|
21
|
+
// No hooks: gemini rows carry no badge, no extra menu item and no derived
|
|
22
|
+
// colour, so the shared panel renders them unchanged.
|
|
23
|
+
// The four-pointed spark of the Gemini mark: four tips on the box edges, each
|
|
24
|
+
// pair joined by a quadratic whose control point is the centre, which is what
|
|
25
|
+
// pinches the sides inwards. Single path, `jp-icon3` so the theme drives the
|
|
26
|
+
// fill in both light and dark; the 16px box matches every other icon in the
|
|
27
|
+
// sidebar.
|
|
28
|
+
const geminiSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
|
|
29
|
+
<path class="jp-icon3" fill="#616161" d="M8 0Q8 8 16 8Q8 8 8 16Q8 8 0 8Q8 8 8 0Z"/>
|
|
30
|
+
</svg>`;
|
|
31
|
+
// Gemini's own names for its two launch surfaces. Kept in the assistant's
|
|
32
|
+
// terminology rather than normalised, because each is both the settings key
|
|
33
|
+
// under `providers.gemini.` and the mode token the server maps to a CLI flag.
|
|
34
|
+
const YOLO_MODE = 'yoloMode';
|
|
35
|
+
const APPROVAL_MODE = 'approvalMode';
|
|
36
|
+
export const descriptor = {
|
|
37
|
+
id: 'gemini',
|
|
38
|
+
label: 'Gemini',
|
|
39
|
+
panelTitle: 'Gemini Sessions',
|
|
40
|
+
iconName: 'jupyterlab_ai_code_assistants_extension:gemini',
|
|
41
|
+
iconSvg: geminiSvgStr,
|
|
42
|
+
cliBinary: 'gemini',
|
|
43
|
+
// No fork flag exists, so the server copies the chat file under a fresh id
|
|
44
|
+
// and the launch resumes that id like any other conversation.
|
|
45
|
+
forkStrategy: 'server-copy',
|
|
46
|
+
colourSource: 'none',
|
|
47
|
+
// The fork's name is written into the copy by the server; the CLI has no
|
|
48
|
+
// naming flag to take it.
|
|
49
|
+
namingStrategy: 'server-side',
|
|
50
|
+
// `--session-id <uuid>` starts a conversation under an id we mint.
|
|
51
|
+
mintsNewSessionId: true,
|
|
52
|
+
launchModes: [
|
|
53
|
+
{
|
|
54
|
+
id: YOLO_MODE,
|
|
55
|
+
title: 'YOLO mode',
|
|
56
|
+
description: 'When enabled, newly spawned and resumed sessions are launched with `--yolo`. Gemini auto-approves every tool call without asking - only enable in workspaces you trust.',
|
|
57
|
+
kind: 'boolean',
|
|
58
|
+
default: false,
|
|
59
|
+
menuLabel: 'YOLO'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: APPROVAL_MODE,
|
|
63
|
+
title: 'Approval mode',
|
|
64
|
+
description: 'Approval ladder passed as `--approval-mode` when set to a value other than the default. A non-default value here takes precedence over the YOLO switch; only the forced YOLO menu action overrides it. `default` prompts for approval, `auto_edit` auto-approves edit tools, `yolo` auto-approves every tool, `plan` is read-only.',
|
|
65
|
+
kind: 'enum',
|
|
66
|
+
values: ['default', 'auto_edit', 'yolo', 'plan'],
|
|
67
|
+
default: 'default'
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
hasRemoteControl: false,
|
|
71
|
+
hasBgAgents: false,
|
|
72
|
+
hasLiveProcess: false
|
|
73
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The single registration point for assistants.
|
|
2
|
+
//
|
|
3
|
+
// One line per provider. Adding an assistant means adding its module and its
|
|
4
|
+
// line here; removing one means deleting both. No core file is edited either
|
|
5
|
+
// way, and nothing outside this directory names an assistant.
|
|
6
|
+
//
|
|
7
|
+
// A provider module exports a `descriptor` (pure data - the settings-schema
|
|
8
|
+
// generator reads it under plain Node) and optionally `hooks` (the DOM and
|
|
9
|
+
// JupyterLab-aware parts). Keep module-scope side effects out of both, so the
|
|
10
|
+
// generator can import this barrel without a browser.
|
|
11
|
+
import * as claude from './claude';
|
|
12
|
+
import * as codex from './codex';
|
|
13
|
+
import * as kimi from './kimi';
|
|
14
|
+
import * as gemini from './gemini';
|
|
15
|
+
export const PROVIDERS = [claude, codex, kimi, gemini];
|
|
16
|
+
export default PROVIDERS;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IProviderDescriptor, IProviderHooks } from '../core/types';
|
|
2
|
+
export declare const MENU_TITLE_COLUMNS = 60;
|
|
3
|
+
/** Trim `text` to `maxColumns` display columns, appending an ellipsis when
|
|
4
|
+
* anything was cut. Iterates by CODE POINT, so an astral character is never
|
|
5
|
+
* split into a lone surrogate (which chromium paints as the replacement
|
|
6
|
+
* glyph). Returns `text` unchanged when it already fits. */
|
|
7
|
+
export declare function truncateToColumns(text: string, maxColumns: number): string;
|
|
8
|
+
/** The distinguishing part of a kimi session id.
|
|
9
|
+
*
|
|
10
|
+
* Kimi ids are `session_<uuid>`, so the core's front-slice would render the
|
|
11
|
+
* constant `session_` for every conversation of a project - the exact thing
|
|
12
|
+
* the short id exists to tell apart. Slice past the prefix instead.
|
|
13
|
+
*/
|
|
14
|
+
export declare function shortSessionId(sessionId: string): string;
|
|
15
|
+
/** Menu-item label for one branch: the conversation title trimmed to the
|
|
16
|
+
* column budget, followed by the short session id. Only the TITLE is trimmed -
|
|
17
|
+
* branches of one project share a path, so the id is what tells them apart and
|
|
18
|
+
* it must survive. The bracketed id is dropped when the title already IS the
|
|
19
|
+
* id (the server's last-resort fallback), which can never be truncated since a
|
|
20
|
+
* short id is at most 8 characters. */
|
|
21
|
+
export declare function branchMenuLabel(label: string, shortId: string): string;
|
|
22
|
+
export declare const descriptor: IProviderDescriptor;
|
|
23
|
+
export declare const hooks: IProviderHooks;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// The Kimi provider - Moonshot AI's `kimi` CLI.
|
|
2
|
+
//
|
|
3
|
+
// Ported from jupyterlab_kimi_code_extension v0.7.8. Everything that made that
|
|
4
|
+
// extension different from the base one is declared here as descriptor data,
|
|
5
|
+
// so no core file knows this assistant exists:
|
|
6
|
+
//
|
|
7
|
+
// * `forkStrategy: 'server-copy'` - kimi has no fork verb at all, so the
|
|
8
|
+
// server copies the session directory and answers with the new id
|
|
9
|
+
// * `colourSource: 'derived'` - kimi has no `/color`, so the default tint is a
|
|
10
|
+
// stable hash of the conversation id (a user-set colour still wins, per the
|
|
11
|
+
// Colour section of the acceptance criteria)
|
|
12
|
+
// * `namingStrategy: 'server-side'` - the name is stamped into the copied
|
|
13
|
+
// `state.json`, not passed to the CLI
|
|
14
|
+
// * one launch mode, `--yolo`, under kimi's own name
|
|
15
|
+
//
|
|
16
|
+
// The only hook is the branch label: kimi's conversation titles are
|
|
17
|
+
// auto-generated by a Chinese-first model, and both the session id shape and
|
|
18
|
+
// the glyph widths of those titles need handling the shared default cannot do.
|
|
19
|
+
// Crescent moon (Kimi is Moonshot AI's CLI) - an outer semicircle on the left,
|
|
20
|
+
// bitten from the right by a wider inner arc.
|
|
21
|
+
const kimiSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
|
|
22
|
+
<g class="jp-icon3" fill="#616161">
|
|
23
|
+
<path d="M8 1.5A6.5 6.5 0 1 0 8 14.5 8 8 0 0 1 8 1.5Z"/>
|
|
24
|
+
</g>
|
|
25
|
+
</svg>`;
|
|
26
|
+
// ------------------------------------------------------------------- labels
|
|
27
|
+
// Budget is in COLUMNS, not characters. Han, Kana, Hangul and emoji render at
|
|
28
|
+
// roughly one em against Latin's half, so counting characters bounds nothing:
|
|
29
|
+
// 60 Han glyphs measured 851-862px in a real Lumino submenu, at or above the
|
|
30
|
+
// 850px that filed the defect in the first place. Kimi is Moonshot AI's CLI,
|
|
31
|
+
// so a Chinese auto-generated title is the expected case, not an exotic one.
|
|
32
|
+
export const MENU_TITLE_COLUMNS = 60;
|
|
33
|
+
// East Asian Wide and Fullwidth ranges, plus emoji. Deliberately coarse: this
|
|
34
|
+
// bounds a menu width, so a handful of mis-classified glyphs cost pixels, not
|
|
35
|
+
// correctness. Anything outside these ranges counts as one column.
|
|
36
|
+
const WIDE_RANGES = [
|
|
37
|
+
[0x1100, 0x115f], // Hangul Jamo
|
|
38
|
+
[0x2e80, 0x303e], // CJK radicals, Kangxi, CJK symbols and punctuation
|
|
39
|
+
[0x3041, 0x33ff], // Hiragana, Katakana, Bopomofo, Hangul Compat, CJK Compat
|
|
40
|
+
[0x3400, 0x4dbf], // CJK Unified Extension A
|
|
41
|
+
[0x4e00, 0x9fff], // CJK Unified Ideographs
|
|
42
|
+
[0xa000, 0xa4cf], // Yi
|
|
43
|
+
[0xac00, 0xd7a3], // Hangul syllables
|
|
44
|
+
[0xf900, 0xfaff], // CJK Compatibility Ideographs
|
|
45
|
+
[0xfe30, 0xfe6f], // CJK Compatibility Forms
|
|
46
|
+
[0xff00, 0xff60], // Fullwidth forms
|
|
47
|
+
[0xffe0, 0xffe6], // Fullwidth signs
|
|
48
|
+
[0x1f300, 0x1faff], // Emoji and pictographs
|
|
49
|
+
[0x20000, 0x3fffd] // CJK Unified Extensions B and beyond
|
|
50
|
+
];
|
|
51
|
+
function isWide(codePoint) {
|
|
52
|
+
return WIDE_RANGES.some(([lo, hi]) => codePoint >= lo && codePoint <= hi);
|
|
53
|
+
}
|
|
54
|
+
/** Trim `text` to `maxColumns` display columns, appending an ellipsis when
|
|
55
|
+
* anything was cut. Iterates by CODE POINT, so an astral character is never
|
|
56
|
+
* split into a lone surrogate (which chromium paints as the replacement
|
|
57
|
+
* glyph). Returns `text` unchanged when it already fits. */
|
|
58
|
+
export function truncateToColumns(text, maxColumns) {
|
|
59
|
+
let columns = 0;
|
|
60
|
+
let kept = '';
|
|
61
|
+
for (const ch of text) {
|
|
62
|
+
const width = isWide(ch.codePointAt(0)) ? 2 : 1;
|
|
63
|
+
if (columns + width > maxColumns) {
|
|
64
|
+
// The cut can land just after a space; drop it so the ellipsis hugs the
|
|
65
|
+
// last word. `trimEnd` is ES2019 and this project targets ES2018.
|
|
66
|
+
return `${kept.replace(/\s+$/, '')}…`;
|
|
67
|
+
}
|
|
68
|
+
columns += width;
|
|
69
|
+
kept += ch;
|
|
70
|
+
}
|
|
71
|
+
return text;
|
|
72
|
+
}
|
|
73
|
+
/** The distinguishing part of a kimi session id.
|
|
74
|
+
*
|
|
75
|
+
* Kimi ids are `session_<uuid>`, so the core's front-slice would render the
|
|
76
|
+
* constant `session_` for every conversation of a project - the exact thing
|
|
77
|
+
* the short id exists to tell apart. Slice past the prefix instead.
|
|
78
|
+
*/
|
|
79
|
+
export function shortSessionId(sessionId) {
|
|
80
|
+
return sessionId.startsWith('session_')
|
|
81
|
+
? sessionId.slice(8, 16)
|
|
82
|
+
: sessionId.slice(0, 8);
|
|
83
|
+
}
|
|
84
|
+
/** Menu-item label for one branch: the conversation title trimmed to the
|
|
85
|
+
* column budget, followed by the short session id. Only the TITLE is trimmed -
|
|
86
|
+
* branches of one project share a path, so the id is what tells them apart and
|
|
87
|
+
* it must survive. The bracketed id is dropped when the title already IS the
|
|
88
|
+
* id (the server's last-resort fallback), which can never be truncated since a
|
|
89
|
+
* short id is at most 8 characters. */
|
|
90
|
+
export function branchMenuLabel(label, shortId) {
|
|
91
|
+
const title = truncateToColumns(label, MENU_TITLE_COLUMNS);
|
|
92
|
+
return label === shortId ? title : `${title} (${shortId})`;
|
|
93
|
+
}
|
|
94
|
+
// -------------------------------------------------------------- descriptor
|
|
95
|
+
export const descriptor = {
|
|
96
|
+
id: 'kimi',
|
|
97
|
+
label: 'Kimi',
|
|
98
|
+
panelTitle: 'Kimi Code Sessions',
|
|
99
|
+
iconName: 'jupyterlab_ai_code_assistants_extension:kimi',
|
|
100
|
+
iconSvg: kimiSvgStr,
|
|
101
|
+
cliBinary: 'kimi',
|
|
102
|
+
// No fork flag exists, so the server copies the session directory under a
|
|
103
|
+
// fresh id and the launch resumes that id like any other conversation.
|
|
104
|
+
forkStrategy: 'server-copy',
|
|
105
|
+
// No `/color` command either: the tint is derived from the conversation id.
|
|
106
|
+
// The core's own FNV-1a is the same hash over the same six ids the retired
|
|
107
|
+
// extension used, so every conversation keeps the colour it already had.
|
|
108
|
+
colourSource: 'derived',
|
|
109
|
+
// The fork's name is written into the copy's `state.json` by the server; the
|
|
110
|
+
// CLI has no naming flag to take it.
|
|
111
|
+
namingStrategy: 'server-side',
|
|
112
|
+
// A bare `kimi` mints its own id and writes it on the first turn, and `-S`
|
|
113
|
+
// only ever resumes - so a new conversation cannot be launched under an id
|
|
114
|
+
// we chose, and is identified from the store on the next poll instead.
|
|
115
|
+
mintsNewSessionId: false,
|
|
116
|
+
launchModes: [
|
|
117
|
+
{
|
|
118
|
+
id: 'yoloMode',
|
|
119
|
+
title: 'YOLO mode',
|
|
120
|
+
description: 'When enabled, newly spawned and resumed sessions are launched with `--yolo`. Kimi auto-approves regular tool calls without asking - only enable in workspaces you trust.',
|
|
121
|
+
kind: 'boolean',
|
|
122
|
+
default: false,
|
|
123
|
+
menuLabel: 'YOLO'
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
hasRemoteControl: false,
|
|
127
|
+
hasBgAgents: false,
|
|
128
|
+
hasLiveProcess: false,
|
|
129
|
+
// Retired standalone extension this provider replaces.
|
|
130
|
+
legacyPluginId: 'jupyterlab_kimi_code_extension'
|
|
131
|
+
};
|
|
132
|
+
// ------------------------------------------------------------------- hooks
|
|
133
|
+
export const hooks = {
|
|
134
|
+
/** Lumino sets no `max-width` on `.lm-Menu-itemLabel`, so an uncapped
|
|
135
|
+
* auto-generated title stretches the submenu across the window. The core's
|
|
136
|
+
* `shortId` argument is a front-slice, which is the constant `session_` for
|
|
137
|
+
* every kimi id, so the id is re-derived here. */
|
|
138
|
+
branchLabel: (branch, _shortId) => branchMenuLabel(branch.label, shortSessionId(branch.session_id))
|
|
139
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jupyterlab_ai_code_assistants_extension",
|
|
3
|
+
"version": "0.6.15",
|
|
4
|
+
"description": "Jupyterlab extension to replace individual jupyterlab_*_code_extension and integrate into one, that offers joint capability, joint settings page and individual right toolbar panels per code assistant, with the ability in settings to decide which code assistant support is on (default - all are enabled)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/stellarshenson/jupyterlab_ai_code_assistants_extension",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/stellarshenson/jupyterlab_ai_code_assistants_extension/issues"
|
|
13
|
+
},
|
|
14
|
+
"license": "BSD-3-Clause",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Stellars Henson",
|
|
17
|
+
"email": "konrad.jelen+github@gmail.com"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
21
|
+
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
|
|
22
|
+
"src/**/*.{ts,tsx}",
|
|
23
|
+
"schema/*.json"
|
|
24
|
+
],
|
|
25
|
+
"main": "lib/index.js",
|
|
26
|
+
"types": "lib/index.d.ts",
|
|
27
|
+
"style": "style/index.css",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/stellarshenson/jupyterlab_ai_code_assistants_extension.git"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "jlpm build:lib && jlpm generate:schema && jlpm build:labextension:dev",
|
|
34
|
+
"build:prod": "jlpm clean && jlpm build:lib:prod && jlpm generate:schema && jlpm build:labextension",
|
|
35
|
+
"build:labextension": "jupyter-builder build .",
|
|
36
|
+
"build:labextension:dev": "jupyter-builder build --development True .",
|
|
37
|
+
"build:lib": "tsc --sourceMap",
|
|
38
|
+
"build:lib:prod": "tsc",
|
|
39
|
+
"clean": "jlpm clean:lib",
|
|
40
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
41
|
+
"clean:lintcache": "rimraf .eslintcache .stylelintcache",
|
|
42
|
+
"clean:labextension": "rimraf jupyterlab_ai_code_assistants_extension/labextension jupyterlab_ai_code_assistants_extension/_version.py",
|
|
43
|
+
"clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
|
|
44
|
+
"eslint": "jlpm eslint:check --fix",
|
|
45
|
+
"eslint:check": "eslint . --cache",
|
|
46
|
+
"generate:schema": "node scripts/generate-schema.mjs && prettier --write schema/plugin.json",
|
|
47
|
+
"install:extension": "jlpm build",
|
|
48
|
+
"lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
|
|
49
|
+
"lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
|
|
50
|
+
"prettier": "jlpm prettier:base --write --list-different",
|
|
51
|
+
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
|
52
|
+
"prettier:check": "jlpm prettier:base --check",
|
|
53
|
+
"stylelint": "jlpm stylelint:check --fix",
|
|
54
|
+
"stylelint:check": "stylelint --cache \"style/**/*.css\"",
|
|
55
|
+
"test": "jest --coverage",
|
|
56
|
+
"watch": "run-p watch:src watch:labextension",
|
|
57
|
+
"watch:src": "tsc -w --sourceMap",
|
|
58
|
+
"watch:labextension": "jupyter-builder watch ."
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@jupyterlab/application": "^4.0.0",
|
|
62
|
+
"@jupyterlab/apputils": "^4.0.0",
|
|
63
|
+
"@jupyterlab/coreutils": "^6.0.0",
|
|
64
|
+
"@jupyterlab/filebrowser": "^4.0.0",
|
|
65
|
+
"@jupyterlab/services": "^7.0.0",
|
|
66
|
+
"@jupyterlab/settingregistry": "^4.0.0",
|
|
67
|
+
"@jupyterlab/terminal": "^4.0.0",
|
|
68
|
+
"@jupyterlab/ui-components": "^4.0.0",
|
|
69
|
+
"@lumino/commands": "^2.0.0",
|
|
70
|
+
"@lumino/coreutils": "^2.0.0",
|
|
71
|
+
"@lumino/disposable": "^2.0.0",
|
|
72
|
+
"@lumino/messaging": "^2.0.0",
|
|
73
|
+
"@lumino/widgets": "^2.0.0",
|
|
74
|
+
"jupyterlab_colourful_tab_extension": "^1.0.19"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@eslint/js": "^9.0.0",
|
|
78
|
+
"@jupyter/builder": "^1.2.0",
|
|
79
|
+
"@jupyter/eslint-plugin": "^0.0.5",
|
|
80
|
+
"@jupyterlab/testutils": "^4.0.0",
|
|
81
|
+
"@types/jest": "^29.2.0",
|
|
82
|
+
"@types/json-schema": "^7.0.11",
|
|
83
|
+
"eslint": "^9.0.0",
|
|
84
|
+
"eslint-config-prettier": "^9.0.0",
|
|
85
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
86
|
+
"globals": "^15.0.0",
|
|
87
|
+
"jest": "^29.2.0",
|
|
88
|
+
"mkdirp": "^1.0.3",
|
|
89
|
+
"npm-run-all2": "^7.0.1",
|
|
90
|
+
"prettier": "^3.0.0",
|
|
91
|
+
"rimraf": "^5.0.1",
|
|
92
|
+
"stylelint": "^15.10.1",
|
|
93
|
+
"stylelint-config-recommended": "^13.0.0",
|
|
94
|
+
"stylelint-config-standard": "^34.0.0",
|
|
95
|
+
"stylelint-csstree-validator": "^3.0.0",
|
|
96
|
+
"stylelint-prettier": "^4.0.0",
|
|
97
|
+
"typescript": "~5.5.4",
|
|
98
|
+
"typescript-eslint": "^8.0.0"
|
|
99
|
+
},
|
|
100
|
+
"resolutions": {
|
|
101
|
+
"lib0": "0.2.111",
|
|
102
|
+
"webpack": "5.106.0",
|
|
103
|
+
"chalk": "4.1.2"
|
|
104
|
+
},
|
|
105
|
+
"overrides": {
|
|
106
|
+
"webpack": "5.106.0",
|
|
107
|
+
"chalk": "4.1.2"
|
|
108
|
+
},
|
|
109
|
+
"sideEffects": [
|
|
110
|
+
"style/*.css",
|
|
111
|
+
"style/index.js"
|
|
112
|
+
],
|
|
113
|
+
"styleModule": "style/index.js",
|
|
114
|
+
"publishConfig": {
|
|
115
|
+
"access": "public"
|
|
116
|
+
},
|
|
117
|
+
"jupyterlab": {
|
|
118
|
+
"discovery": {
|
|
119
|
+
"server": {
|
|
120
|
+
"managers": [
|
|
121
|
+
"pip"
|
|
122
|
+
],
|
|
123
|
+
"base": {
|
|
124
|
+
"name": "jupyterlab_ai_code_assistants_extension"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"extension": true,
|
|
129
|
+
"outputDir": "jupyterlab_ai_code_assistants_extension/labextension",
|
|
130
|
+
"schemaDir": "schema",
|
|
131
|
+
"sharedPackages": {
|
|
132
|
+
"jupyterlab_colourful_tab_extension": {
|
|
133
|
+
"bundled": false,
|
|
134
|
+
"singleton": true
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"prettier": {
|
|
139
|
+
"singleQuote": true,
|
|
140
|
+
"trailingComma": "none",
|
|
141
|
+
"arrowParens": "avoid",
|
|
142
|
+
"endOfLine": "auto",
|
|
143
|
+
"overrides": [
|
|
144
|
+
{
|
|
145
|
+
"files": "package.json",
|
|
146
|
+
"options": {
|
|
147
|
+
"tabWidth": 4
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
"stylelint": {
|
|
153
|
+
"extends": [
|
|
154
|
+
"stylelint-config-recommended",
|
|
155
|
+
"stylelint-config-standard",
|
|
156
|
+
"stylelint-prettier/recommended"
|
|
157
|
+
],
|
|
158
|
+
"plugins": [
|
|
159
|
+
"stylelint-csstree-validator"
|
|
160
|
+
],
|
|
161
|
+
"rules": {
|
|
162
|
+
"csstree/validator": true,
|
|
163
|
+
"property-no-vendor-prefix": null,
|
|
164
|
+
"selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
|
|
165
|
+
"selector-no-vendor-prefix": null,
|
|
166
|
+
"value-no-vendor-prefix": null
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "AI Code Assistants",
|
|
3
|
+
"description": "One settings section for every AI code assistant panel. Generated from the provider registry by `jlpm generate:schema` - edit the provider descriptors, not this file.",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"jupyter.lab.setting-icon": "jupyterlab_ai_code_assistants_extension:assistants",
|
|
6
|
+
"jupyter.lab.setting-icon-label": "AI Code Assistants",
|
|
7
|
+
"properties": {
|
|
8
|
+
"presentationMode": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "Presentation mode",
|
|
11
|
+
"description": "How session rows are labelled, in every assistant's panel. `name` (default) shows the session name the assistant records for the project; the initial name is the project folder name, then the path is walked up to disambiguate when two projects share a folder name. `path` shows the project path relative to the JupyterLab notebook root (absolute if outside it).",
|
|
12
|
+
"enum": ["name", "path"],
|
|
13
|
+
"default": "name"
|
|
14
|
+
},
|
|
15
|
+
"recentLimit": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"title": "Recent items count",
|
|
18
|
+
"description": "Number of sessions listed in the Recent section, sorted by last activity (descending). The section displays up to 10 rows and scrolls for the rest.",
|
|
19
|
+
"default": 10,
|
|
20
|
+
"minimum": 1,
|
|
21
|
+
"maximum": 100
|
|
22
|
+
},
|
|
23
|
+
"colouredTabs": {
|
|
24
|
+
"type": "boolean",
|
|
25
|
+
"title": "Coloured terminal tabs",
|
|
26
|
+
"description": "When enabled (default), a terminal running an assistant has its dock tab tinted with that conversation's colour. Turning it off clears the tint and stops it being applied. Requires `jupyterlab_colourful_tab_extension`; without it there is no tint either way.",
|
|
27
|
+
"default": true
|
|
28
|
+
},
|
|
29
|
+
"sidebar": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"title": "Sidebar position",
|
|
32
|
+
"description": "Which JupyterLab sidebar to dock the assistant panels to. `right` (default) keeps them clear of the file browser. `left` puts them next to it.",
|
|
33
|
+
"enum": ["left", "right"],
|
|
34
|
+
"default": "right"
|
|
35
|
+
},
|
|
36
|
+
"providers.claude.enabled": {
|
|
37
|
+
"type": "boolean",
|
|
38
|
+
"title": "Claude Code: enabled",
|
|
39
|
+
"description": "Show the Claude Code Sessions panel. A panel appears only when this is on AND the `claude` binary is on PATH.",
|
|
40
|
+
"default": true
|
|
41
|
+
},
|
|
42
|
+
"providers.claude.dangerouslySkipPermissions": {
|
|
43
|
+
"type": "boolean",
|
|
44
|
+
"title": "Claude Code: Dangerously skip permissions",
|
|
45
|
+
"description": "When enabled, newly spawned and resumed sessions are launched with `--dangerously-skip-permissions`. Bypasses every Claude Code permission prompt - only enable in sandboxes you trust.",
|
|
46
|
+
"default": false
|
|
47
|
+
},
|
|
48
|
+
"providers.codex.enabled": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"title": "Codex: enabled",
|
|
51
|
+
"description": "Show the Codex Sessions panel. A panel appears only when this is on AND the `codex` binary is on PATH.",
|
|
52
|
+
"default": true
|
|
53
|
+
},
|
|
54
|
+
"providers.codex.dangerouslyBypassApprovalsAndSandbox": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"title": "Codex: Bypass Codex approvals and sandbox",
|
|
57
|
+
"description": "When enabled, newly spawned and resumed sessions are launched with `--dangerously-bypass-approvals-and-sandbox`. Bypasses every Codex approval prompt and sandbox - only enable in environments you trust.",
|
|
58
|
+
"default": false
|
|
59
|
+
},
|
|
60
|
+
"providers.gemini.enabled": {
|
|
61
|
+
"type": "boolean",
|
|
62
|
+
"title": "Gemini: enabled",
|
|
63
|
+
"description": "Show the Gemini Sessions panel. A panel appears only when this is on AND the `gemini` binary is on PATH.",
|
|
64
|
+
"default": true
|
|
65
|
+
},
|
|
66
|
+
"providers.gemini.yoloMode": {
|
|
67
|
+
"type": "boolean",
|
|
68
|
+
"title": "Gemini: YOLO mode",
|
|
69
|
+
"description": "When enabled, newly spawned and resumed sessions are launched with `--yolo`. Gemini auto-approves every tool call without asking - only enable in workspaces you trust.",
|
|
70
|
+
"default": false
|
|
71
|
+
},
|
|
72
|
+
"providers.gemini.approvalMode": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"title": "Gemini: Approval mode",
|
|
75
|
+
"description": "Approval ladder passed as `--approval-mode` when set to a value other than the default. A non-default value here takes precedence over the YOLO switch; only the forced YOLO menu action overrides it. `default` prompts for approval, `auto_edit` auto-approves edit tools, `yolo` auto-approves every tool, `plan` is read-only.",
|
|
76
|
+
"default": "default",
|
|
77
|
+
"enum": ["default", "auto_edit", "yolo", "plan"]
|
|
78
|
+
},
|
|
79
|
+
"providers.kimi.enabled": {
|
|
80
|
+
"type": "boolean",
|
|
81
|
+
"title": "Kimi: enabled",
|
|
82
|
+
"description": "Show the Kimi Code Sessions panel. A panel appears only when this is on AND the `kimi` binary is on PATH.",
|
|
83
|
+
"default": true
|
|
84
|
+
},
|
|
85
|
+
"providers.kimi.yoloMode": {
|
|
86
|
+
"type": "boolean",
|
|
87
|
+
"title": "Kimi: YOLO mode",
|
|
88
|
+
"description": "When enabled, newly spawned and resumed sessions are launched with `--yolo`. Kimi auto-approves regular tool calls without asking - only enable in workspaces you trust.",
|
|
89
|
+
"default": false
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"additionalProperties": true
|
|
93
|
+
}
|