@openclaw/plugin-inspector 0.3.14 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.3.15 - 2026-06-12
6
+
7
+ ### Fixed
8
+
9
+ - Detect deprecated `loadSessionStore(...)` usage when plugin code calls it through a runtime session API alias.
10
+
3
11
  ## 0.3.14 - 2026-06-11
4
12
 
5
13
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/plugin-inspector",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "private": false,
5
5
  "description": "Offline compatibility inspector for OpenClaw plugins.",
6
6
  "type": "module",
@@ -35,6 +35,7 @@ function collectLoadSessionStoreDeprecations(findings, context) {
35
35
  collectNamespaceUsageDeprecations(findings, context);
36
36
  collectNamespaceRequireDeprecations(findings, context);
37
37
  collectRuntimeUsageDeprecations(findings, context);
38
+ collectRuntimeAliasUsageDeprecations(findings, context);
38
39
  }
39
40
 
40
41
  function collectNamedImportDeprecations(findings, context) {
@@ -298,6 +299,172 @@ function collectRuntimeUsageDeprecations(findings, context) {
298
299
  });
299
300
  }
300
301
 
302
+ function collectRuntimeAliasUsageDeprecations(findings, context) {
303
+ const aliases = collectRuntimeSessionAliases(context.text);
304
+ if (aliases.size === 0) {
305
+ return;
306
+ }
307
+ collectMemberCallDeprecations(findings, context, {
308
+ receiverMatcher: (receiver) => aliases.has(receiver),
309
+ surface: "api.runtime.agent.session alias",
310
+ });
311
+ }
312
+
313
+ function collectRuntimeSessionAliases(text) {
314
+ const aliases = new Set();
315
+ const factories = collectRuntimeSessionFactoryNames(text);
316
+ collectDirectRuntimeSessionAliases(text, aliases);
317
+ collectFactoryCallRuntimeSessionAliases(text, aliases, factories);
318
+ return aliases;
319
+ }
320
+
321
+ function collectRuntimeSessionFactoryNames(text) {
322
+ const factories = new Set();
323
+ for (const fn of findNamedFunctionBodies(text)) {
324
+ const aliases = new Set();
325
+ collectDirectRuntimeSessionAliases(fn.body, aliases);
326
+ if (aliases.size === 0) {
327
+ continue;
328
+ }
329
+ const returnRegex = /\breturn\s+([A-Za-z_$][\w$]*)\b/g;
330
+ for (const match of fn.body.matchAll(returnRegex)) {
331
+ if (aliases.has(match[1])) {
332
+ factories.add(fn.name);
333
+ }
334
+ }
335
+ }
336
+ return factories;
337
+ }
338
+
339
+ function findNamedFunctionBodies(text) {
340
+ const functions = [];
341
+ let searchStart = 0;
342
+ while (searchStart < text.length) {
343
+ const keywordOffset = text.indexOf("function", searchStart);
344
+ if (keywordOffset === -1) {
345
+ break;
346
+ }
347
+ searchStart = keywordOffset + "function".length;
348
+ if (!isIdentifierBoundary(text, keywordOffset - 1) || !isIdentifierBoundary(text, searchStart)) {
349
+ continue;
350
+ }
351
+ let cursor = skipWhitespaceForward(text, searchStart);
352
+ const name = readIdentifierAt(text, cursor);
353
+ if (!name) {
354
+ continue;
355
+ }
356
+ cursor = skipWhitespaceForward(text, name.end);
357
+ if (text[cursor] !== "(") {
358
+ continue;
359
+ }
360
+ const paramsEnd = findMatchingDelimiter(text, cursor, "(", ")");
361
+ if (paramsEnd === -1) {
362
+ continue;
363
+ }
364
+ cursor = skipWhitespaceForward(text, paramsEnd + 1);
365
+ while (cursor < text.length && text[cursor] !== "{") {
366
+ cursor += 1;
367
+ }
368
+ if (text[cursor] !== "{") {
369
+ break;
370
+ }
371
+ const bodyStart = cursor + 1;
372
+ const bodyEnd = findMatchingBrace(text, cursor);
373
+ if (bodyEnd === -1) {
374
+ continue;
375
+ }
376
+ functions.push({
377
+ name: name.value,
378
+ body: text.slice(bodyStart, bodyEnd),
379
+ });
380
+ searchStart = bodyEnd + 1;
381
+ }
382
+ return functions;
383
+ }
384
+
385
+ function readIdentifierAt(text, startOffset) {
386
+ const first = text[startOffset];
387
+ if (!/[A-Za-z_$]/.test(first)) {
388
+ return null;
389
+ }
390
+ let end = startOffset + 1;
391
+ while (end < text.length && /[A-Za-z0-9_$]/.test(text[end])) {
392
+ end += 1;
393
+ }
394
+ return {
395
+ value: text.slice(startOffset, end),
396
+ end,
397
+ };
398
+ }
399
+
400
+ function findMatchingDelimiter(text, openOffset, openChar, closeChar) {
401
+ let depth = 0;
402
+ for (let index = openOffset; index < text.length; index += 1) {
403
+ const char = text[index];
404
+ if (char === openChar) {
405
+ depth += 1;
406
+ } else if (char === closeChar) {
407
+ depth -= 1;
408
+ if (depth === 0) {
409
+ return index;
410
+ }
411
+ }
412
+ }
413
+ return -1;
414
+ }
415
+
416
+ function findMatchingBrace(text, openOffset) {
417
+ return findMatchingDelimiter(text, openOffset, "{", "}");
418
+ }
419
+
420
+ function collectDirectRuntimeSessionAliases(text, aliases) {
421
+ const runtimeAliases = collectRuntimeObjectAliases(text);
422
+ const declarationRegex = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*([^;\n]+)/g;
423
+ for (const match of text.matchAll(declarationRegex)) {
424
+ const local = match[1];
425
+ const initializer = normalizeReceiverExpression(match[2]);
426
+ if (isRuntimeSessionExpression(initializer, runtimeAliases)) {
427
+ aliases.add(local);
428
+ }
429
+ }
430
+ }
431
+
432
+ function collectRuntimeObjectAliases(text) {
433
+ const aliases = new Set();
434
+ const declarationRegex = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:\([^)]*\)\s*)?(?:[A-Za-z_$][\w$]*|this)\.runtime\b/g;
435
+ for (const match of text.matchAll(declarationRegex)) {
436
+ aliases.add(match[1]);
437
+ }
438
+ return aliases;
439
+ }
440
+
441
+ function isRuntimeSessionExpression(expression, runtimeAliases) {
442
+ for (const part of expression.split("??")) {
443
+ const candidate = part.trim();
444
+ if (isRuntimeSessionReceiver(candidate)) {
445
+ return true;
446
+ }
447
+ for (const alias of runtimeAliases) {
448
+ if (candidate === `${alias}.agent.session` || candidate === `${alias}.channel.session`) {
449
+ return true;
450
+ }
451
+ }
452
+ }
453
+ return false;
454
+ }
455
+
456
+ function collectFactoryCallRuntimeSessionAliases(text, aliases, factories) {
457
+ if (factories.size === 0) {
458
+ return;
459
+ }
460
+ const declarationRegex = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*([A-Za-z_$][\w$]*)\s*\(/g;
461
+ for (const match of text.matchAll(declarationRegex)) {
462
+ if (factories.has(match[2])) {
463
+ aliases.add(match[1]);
464
+ }
465
+ }
466
+ }
467
+
301
468
  function parseNamedBindings(rawBindings, options = {}) {
302
469
  const aliasSeparator = options.aliasSeparator ?? "as";
303
470
  return rawBindings