jupyterlab_claude_code_extension 1.0.19 → 1.0.21
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/lib/widget.d.ts +13 -1
- package/lib/widget.js +61 -8
- package/package.json +1 -1
- package/src/widget.ts +63 -8
package/lib/widget.d.ts
CHANGED
|
@@ -13,8 +13,20 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
|
|
|
13
13
|
protected onBeforeHide(_msg: Message): void;
|
|
14
14
|
protected onCloseRequest(msg: Message): void;
|
|
15
15
|
private _buildShell;
|
|
16
|
-
/**
|
|
16
|
+
/** Normalise strings for filter comparison: NFD-decompose, strip combining
|
|
17
|
+
* diacritic marks, lowercase, and collapse separators (`-`, `_`, `.`, `/`,
|
|
18
|
+
* whitespace) entirely. So "foo-bar", "foo_bar", "foo bar", "Foo Bar" all
|
|
19
|
+
* compare equal as "foobar".
|
|
20
|
+
*/
|
|
21
|
+
private _normalize;
|
|
22
|
+
/** Strict fuzzy match: substring on normalised strings, with up to 2%
|
|
23
|
+
* Levenshtein tolerance for queries of 6+ chars (so the 98% threshold
|
|
24
|
+
* only relaxes substring strictness when the query is long enough that
|
|
25
|
+
* 2% rounds to a nonzero edit budget - effectively substring-only for
|
|
26
|
+
* short queries).
|
|
27
|
+
*/
|
|
17
28
|
private _fuzzyMatch;
|
|
29
|
+
private _levenshtein;
|
|
18
30
|
private _matchesFilter;
|
|
19
31
|
private _showLoading;
|
|
20
32
|
private _showError;
|
package/lib/widget.js
CHANGED
|
@@ -151,23 +151,76 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
151
151
|
this._bodyEl = body;
|
|
152
152
|
this._statusEl = status;
|
|
153
153
|
}
|
|
154
|
-
/**
|
|
154
|
+
/** Normalise strings for filter comparison: NFD-decompose, strip combining
|
|
155
|
+
* diacritic marks, lowercase, and collapse separators (`-`, `_`, `.`, `/`,
|
|
156
|
+
* whitespace) entirely. So "foo-bar", "foo_bar", "foo bar", "Foo Bar" all
|
|
157
|
+
* compare equal as "foobar".
|
|
158
|
+
*/
|
|
159
|
+
_normalize(s) {
|
|
160
|
+
return s
|
|
161
|
+
.normalize('NFD')
|
|
162
|
+
.replace(/[̀-ͯ]/g, '')
|
|
163
|
+
.toLowerCase()
|
|
164
|
+
.replace(/[\s\-_./]+/g, '');
|
|
165
|
+
}
|
|
166
|
+
/** Strict fuzzy match: substring on normalised strings, with up to 2%
|
|
167
|
+
* Levenshtein tolerance for queries of 6+ chars (so the 98% threshold
|
|
168
|
+
* only relaxes substring strictness when the query is long enough that
|
|
169
|
+
* 2% rounds to a nonzero edit budget - effectively substring-only for
|
|
170
|
+
* short queries).
|
|
171
|
+
*/
|
|
155
172
|
_fuzzyMatch(haystack, needle) {
|
|
156
173
|
if (!needle) {
|
|
157
174
|
return true;
|
|
158
175
|
}
|
|
159
|
-
const h =
|
|
160
|
-
const n =
|
|
176
|
+
const h = this._normalize(haystack);
|
|
177
|
+
const n = this._normalize(needle);
|
|
178
|
+
if (!n) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
161
181
|
if (h.includes(n)) {
|
|
162
182
|
return true;
|
|
163
183
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
184
|
+
const tol = Math.floor(n.length * 0.02);
|
|
185
|
+
if (tol === 0) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
for (let len = n.length - tol; len <= n.length + tol; len += 1) {
|
|
189
|
+
if (len <= 0) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
for (let i = 0; i + len <= h.length; i += 1) {
|
|
193
|
+
if (this._levenshtein(h.slice(i, i + len), n) <= tol) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
_levenshtein(a, b) {
|
|
201
|
+
const m = a.length;
|
|
202
|
+
const n = b.length;
|
|
203
|
+
if (m === 0) {
|
|
204
|
+
return n;
|
|
205
|
+
}
|
|
206
|
+
if (n === 0) {
|
|
207
|
+
return m;
|
|
208
|
+
}
|
|
209
|
+
const dp = new Array(n + 1);
|
|
210
|
+
for (let j = 0; j <= n; j += 1) {
|
|
211
|
+
dp[j] = j;
|
|
212
|
+
}
|
|
213
|
+
for (let i = 1; i <= m; i += 1) {
|
|
214
|
+
let prev = dp[0];
|
|
215
|
+
dp[0] = i;
|
|
216
|
+
for (let j = 1; j <= n; j += 1) {
|
|
217
|
+
const tmp = dp[j];
|
|
218
|
+
dp[j] =
|
|
219
|
+
a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j], dp[j - 1]);
|
|
220
|
+
prev = tmp;
|
|
168
221
|
}
|
|
169
222
|
}
|
|
170
|
-
return
|
|
223
|
+
return dp[n];
|
|
171
224
|
}
|
|
172
225
|
_matchesFilter(s) {
|
|
173
226
|
const q = this._filter.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_claude_code_extension",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "Browse, resume, and manage your Claude Code CLI sessions from a JupyterLab side panel. One click reactivates the right terminal - no duplicate tabs, live remote-control indicator, and favourites for the projects you keep coming back to.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
package/src/widget.ts
CHANGED
|
@@ -186,23 +186,78 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
186
186
|
this._statusEl = status;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
/**
|
|
189
|
+
/** Normalise strings for filter comparison: NFD-decompose, strip combining
|
|
190
|
+
* diacritic marks, lowercase, and collapse separators (`-`, `_`, `.`, `/`,
|
|
191
|
+
* whitespace) entirely. So "foo-bar", "foo_bar", "foo bar", "Foo Bar" all
|
|
192
|
+
* compare equal as "foobar".
|
|
193
|
+
*/
|
|
194
|
+
private _normalize(s: string): string {
|
|
195
|
+
return s
|
|
196
|
+
.normalize('NFD')
|
|
197
|
+
.replace(/[̀-ͯ]/g, '')
|
|
198
|
+
.toLowerCase()
|
|
199
|
+
.replace(/[\s\-_./]+/g, '');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Strict fuzzy match: substring on normalised strings, with up to 2%
|
|
203
|
+
* Levenshtein tolerance for queries of 6+ chars (so the 98% threshold
|
|
204
|
+
* only relaxes substring strictness when the query is long enough that
|
|
205
|
+
* 2% rounds to a nonzero edit budget - effectively substring-only for
|
|
206
|
+
* short queries).
|
|
207
|
+
*/
|
|
190
208
|
private _fuzzyMatch(haystack: string, needle: string): boolean {
|
|
191
209
|
if (!needle) {
|
|
192
210
|
return true;
|
|
193
211
|
}
|
|
194
|
-
const h =
|
|
195
|
-
const n =
|
|
212
|
+
const h = this._normalize(haystack);
|
|
213
|
+
const n = this._normalize(needle);
|
|
214
|
+
if (!n) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
196
217
|
if (h.includes(n)) {
|
|
197
218
|
return true;
|
|
198
219
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
220
|
+
const tol = Math.floor(n.length * 0.02);
|
|
221
|
+
if (tol === 0) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
for (let len = n.length - tol; len <= n.length + tol; len += 1) {
|
|
225
|
+
if (len <= 0) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
for (let i = 0; i + len <= h.length; i += 1) {
|
|
229
|
+
if (this._levenshtein(h.slice(i, i + len), n) <= tol) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private _levenshtein(a: string, b: string): number {
|
|
238
|
+
const m = a.length;
|
|
239
|
+
const n = b.length;
|
|
240
|
+
if (m === 0) {
|
|
241
|
+
return n;
|
|
242
|
+
}
|
|
243
|
+
if (n === 0) {
|
|
244
|
+
return m;
|
|
245
|
+
}
|
|
246
|
+
const dp: number[] = new Array(n + 1);
|
|
247
|
+
for (let j = 0; j <= n; j += 1) {
|
|
248
|
+
dp[j] = j;
|
|
249
|
+
}
|
|
250
|
+
for (let i = 1; i <= m; i += 1) {
|
|
251
|
+
let prev = dp[0];
|
|
252
|
+
dp[0] = i;
|
|
253
|
+
for (let j = 1; j <= n; j += 1) {
|
|
254
|
+
const tmp = dp[j];
|
|
255
|
+
dp[j] =
|
|
256
|
+
a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j], dp[j - 1]);
|
|
257
|
+
prev = tmp;
|
|
203
258
|
}
|
|
204
259
|
}
|
|
205
|
-
return
|
|
260
|
+
return dp[n];
|
|
206
261
|
}
|
|
207
262
|
|
|
208
263
|
private _matchesFilter(s: ISession): boolean {
|