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 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.71",
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
- path === 'status' && settings === serverSettings
859
- ? Promise.resolve(roster())
860
- : Promise.reject(new Error('not this activation'))
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 -