jupyterlab_ai_code_assistants_extension 1.2.71 → 1.2.73
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 +1 -1
- package/lib/index.js +8 -0
- package/package.json +1 -1
- package/src/__tests__/index.spec.ts +38 -5
- package/src/index.ts +8 -0
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ pip install jupyterlab_ai_code_assistants_extension
|
|
|
77
77
|
|
|
78
78
|
## Migrating from the standalone extensions
|
|
79
79
|
|
|
80
|
-
This package supersedes `jupyterlab_claude_code_extension`, `jupyterlab_codex_extension` and `jupyterlab_kimi_code_extension`. On first run it carries their settings and favourites over automatically; uninstall the standalones once you are ready:
|
|
80
|
+
This package supersedes `jupyterlab_claude_code_extension`, `jupyterlab_codex_extension` and `jupyterlab_kimi_code_extension`. On first run it carries their settings and favourites over automatically, and it never replaces a setting you have already saved in this extension; uninstall the standalones once you are ready:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
pip uninstall jupyterlab_claude_code_extension jupyterlab_codex_extension jupyterlab_kimi_code_extension
|
package/lib/index.js
CHANGED
|
@@ -347,6 +347,14 @@ const plugin = {
|
|
|
347
347
|
const result = await requestAPI('migrate', serverSettings, { method: 'POST', body: '{}' });
|
|
348
348
|
for (const entry of (_a = result.migrated) !== null && _a !== void 0 ? _a : []) {
|
|
349
349
|
for (const [key, value] of Object.entries((_b = entry.keys) !== null && _b !== void 0 ? _b : {})) {
|
|
350
|
+
// A value already saved here is the user's newer choice and
|
|
351
|
+
// stays. The marker that stops a second migration lives in the
|
|
352
|
+
// Jupyter data folder, apart from these settings, so a server
|
|
353
|
+
// that shares only the settings folder migrates again and would
|
|
354
|
+
// put the retired extension's value back (DEF-RETI-299).
|
|
355
|
+
if ((settings === null || settings === void 0 ? void 0 : settings.get(key).user) !== undefined) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
350
358
|
// Per key. The server marks EVERY provider migrated before it
|
|
351
359
|
// answers, so one rejection aborting the loop used to drop the
|
|
352
360
|
// remaining providers' values with no retry ever offered again -
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_ai_code_assistants_extension",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.73",
|
|
4
4
|
"description": "A full launcher and manager for every AI code assistant in JupyterLab - Claude Code, Codex, Kimi, Gemini and DeepSeek. Start, resume, fork, switch, and clean up CLI sessions from a side panel per assistant - one click lands you in the right terminal with the assistant already running, no duplicate tabs, no UUID hunting.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -851,14 +851,25 @@ describe('ACC-SETT - settings drive the panels', () => {
|
|
|
851
851
|
saveRejects?: boolean;
|
|
852
852
|
layoutSaveRejects?: boolean;
|
|
853
853
|
shellNotRestored?: boolean;
|
|
854
|
+
/** The `migrated` list `POST migrate` answers with; without it the
|
|
855
|
+
* request fails, as with nothing to carry over. */
|
|
856
|
+
migrated?: unknown[];
|
|
854
857
|
} = {}
|
|
855
858
|
): Promise<ISettingsHarness> {
|
|
856
859
|
const serverSettings = {};
|
|
857
|
-
request.mockImplementation((path: string, settings: unknown) =>
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
860
|
+
request.mockImplementation((path: string, settings: unknown) => {
|
|
861
|
+
if (settings === serverSettings && path === 'status') {
|
|
862
|
+
return Promise.resolve(roster());
|
|
863
|
+
}
|
|
864
|
+
if (
|
|
865
|
+
settings === serverSettings &&
|
|
866
|
+
path === 'migrate' &&
|
|
867
|
+
options.migrated
|
|
868
|
+
) {
|
|
869
|
+
return Promise.resolve({ migrated: options.migrated });
|
|
870
|
+
}
|
|
871
|
+
return Promise.reject(new Error('not this activation'));
|
|
872
|
+
});
|
|
862
873
|
|
|
863
874
|
const docks: [AssistantSessionsPanel, string][] = [];
|
|
864
875
|
const activated: { id: string; afterDocks: number }[] = [];
|
|
@@ -1227,6 +1238,28 @@ describe('ACC-SETT - settings drive the panels', () => {
|
|
|
1227
1238
|
dispose(live);
|
|
1228
1239
|
});
|
|
1229
1240
|
|
|
1241
|
+
// ------------------------------------------------------- DEF-RETI-299
|
|
1242
|
+
|
|
1243
|
+
const SKIP_KEY = 'providers.claude.dangerouslySkipPermissions';
|
|
1244
|
+
const migratedSkip = (value: boolean): unknown[] => [
|
|
1245
|
+
{ provider_id: 'claude', keys: { [SKIP_KEY]: value }, favourites: [] }
|
|
1246
|
+
];
|
|
1247
|
+
|
|
1248
|
+
it('DEF-RETI-299 - a migration run again keeps the value the user saved here', async () => {
|
|
1249
|
+
const live = await activate(
|
|
1250
|
+
{ [SKIP_KEY]: true },
|
|
1251
|
+
{ migrated: migratedSkip(false) }
|
|
1252
|
+
);
|
|
1253
|
+
expect(live.saved).toEqual([]);
|
|
1254
|
+
dispose(live);
|
|
1255
|
+
});
|
|
1256
|
+
|
|
1257
|
+
it('ACC-RETI-85 - a migrated key with nothing saved here is carried over', async () => {
|
|
1258
|
+
const live = await activate({}, { migrated: migratedSkip(true) });
|
|
1259
|
+
expect(live.saved).toEqual([[SKIP_KEY, true]]);
|
|
1260
|
+
dispose(live);
|
|
1261
|
+
});
|
|
1262
|
+
|
|
1230
1263
|
// ------------------------------------------------------- ACC-SETT-189
|
|
1231
1264
|
|
|
1232
1265
|
const MOVE_TO_PROJ = { path: 'proj', dontShowBrowser: true };
|
package/src/index.ts
CHANGED
|
@@ -439,6 +439,14 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
439
439
|
);
|
|
440
440
|
for (const entry of result.migrated ?? []) {
|
|
441
441
|
for (const [key, value] of Object.entries(entry.keys ?? {})) {
|
|
442
|
+
// A value already saved here is the user's newer choice and
|
|
443
|
+
// stays. The marker that stops a second migration lives in the
|
|
444
|
+
// Jupyter data folder, apart from these settings, so a server
|
|
445
|
+
// that shares only the settings folder migrates again and would
|
|
446
|
+
// put the retired extension's value back (DEF-RETI-299).
|
|
447
|
+
if (settings?.get(key).user !== undefined) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
442
450
|
// Per key. The server marks EVERY provider migrated before it
|
|
443
451
|
// answers, so one rejection aborting the loop used to drop the
|
|
444
452
|
// remaining providers' values with no retry ever offered again -
|