explorbot 0.4.6 → 0.4.8

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.
Files changed (74) hide show
  1. package/boat/api-tester/src/ai/chief.ts +3 -1
  2. package/boat/api-tester/src/ai/curler.ts +74 -66
  3. package/boat/api-tester/src/apibot.ts +1 -0
  4. package/boat/api-tester/src/cli.ts +2 -0
  5. package/boat/api-tester/src/config.ts +18 -1
  6. package/dist/boat/api-tester/src/ai/chief.js +3 -1
  7. package/dist/boat/api-tester/src/ai/curler.js +59 -56
  8. package/dist/boat/api-tester/src/apibot.js +1 -0
  9. package/dist/boat/api-tester/src/cli.js +2 -0
  10. package/dist/boat/api-tester/src/config.js +3 -1
  11. package/dist/package.json +2 -2
  12. package/dist/rules/chief/general.md +2 -0
  13. package/dist/rules/researcher/pagination.md +7 -0
  14. package/dist/src/action-result.d.ts +6 -0
  15. package/dist/src/action-result.js +12 -0
  16. package/dist/src/action.js +3 -2
  17. package/dist/src/ai/navigator.js +1 -4
  18. package/dist/src/ai/pilot.js +8 -12
  19. package/dist/src/ai/planner/session-dedup.d.ts +2 -1
  20. package/dist/src/ai/planner/session-dedup.js +18 -1
  21. package/dist/src/ai/planner.js +12 -4
  22. package/dist/src/ai/provider.js +18 -4
  23. package/dist/src/ai/researcher/locators.js +1 -1
  24. package/dist/src/ai/researcher/pagination.d.ts +16 -0
  25. package/dist/src/ai/researcher/pagination.js +62 -0
  26. package/dist/src/ai/researcher/parser.d.ts +3 -0
  27. package/dist/src/ai/researcher/parser.js +22 -6
  28. package/dist/src/ai/researcher/sections.js +1 -1
  29. package/dist/src/ai/researcher.js +7 -2
  30. package/dist/src/ai/rules.js +17 -0
  31. package/dist/src/ai/scout.js +8 -2
  32. package/dist/src/ai/tester.js +1 -1
  33. package/dist/src/ai/tools.js +12 -4
  34. package/dist/src/commands/options/ws-option.d.ts +7 -0
  35. package/dist/src/commands/options/ws-option.js +14 -0
  36. package/dist/src/config.d.ts +1 -0
  37. package/dist/src/config.js +14 -11
  38. package/dist/src/remote.d.ts +2 -0
  39. package/dist/src/remote.js +23 -16
  40. package/dist/src/utils/aria.d.ts +2 -0
  41. package/dist/src/utils/aria.js +6 -1
  42. package/dist/src/utils/code-extractor.js +6 -2
  43. package/dist/src/utils/markdown-query.d.ts +2 -0
  44. package/dist/src/utils/markdown-query.js +39 -0
  45. package/dist/src/utils/pagination.d.ts +16 -0
  46. package/dist/src/utils/pagination.js +20 -0
  47. package/docs/superpowers/plans/2026-09-10-pagination.md +1420 -0
  48. package/docs/superpowers/specs/2026-09-09-pagination-rule-design.md +125 -97
  49. package/package.json +2 -2
  50. package/rules/chief/general.md +2 -0
  51. package/rules/researcher/pagination.md +7 -0
  52. package/src/action-result.ts +16 -0
  53. package/src/action.ts +3 -2
  54. package/src/ai/navigator.ts +1 -4
  55. package/src/ai/pilot.ts +8 -12
  56. package/src/ai/planner/session-dedup.ts +16 -2
  57. package/src/ai/planner.ts +12 -4
  58. package/src/ai/provider.ts +18 -3
  59. package/src/ai/researcher/locators.ts +1 -1
  60. package/src/ai/researcher/pagination.ts +68 -0
  61. package/src/ai/researcher/parser.ts +23 -5
  62. package/src/ai/researcher/sections.ts +1 -1
  63. package/src/ai/researcher.ts +9 -3
  64. package/src/ai/rules.ts +17 -0
  65. package/src/ai/scout.ts +9 -2
  66. package/src/ai/tester.ts +1 -1
  67. package/src/ai/tools.ts +9 -4
  68. package/src/commands/options/ws-option.ts +14 -0
  69. package/src/config.ts +15 -11
  70. package/src/remote.ts +22 -15
  71. package/src/utils/aria.ts +8 -1
  72. package/src/utils/code-extractor.ts +6 -2
  73. package/src/utils/markdown-query.ts +39 -0
  74. package/src/utils/pagination.ts +36 -0
@@ -511,7 +511,12 @@ export const diffAriaSnapshots = (previous, current) => {
511
511
  const renames = detectRenames(prev, curr, prevTotals, currTotals);
512
512
  const added = [...byCount.added, ...renames.added];
513
513
  const removed = [...byCount.removed, ...renames.removed];
514
- return { text: formatDiff(added, removed, toggled, typed), count: added.length + removed.length + toggled.length + typed.length };
514
+ return {
515
+ text: formatDiff(added, removed, toggled, typed),
516
+ count: added.length + removed.length + toggled.length + typed.length,
517
+ added: added.length,
518
+ removed: removed.length,
519
+ };
515
520
  };
516
521
  export const detectFocusArea = (snapshot) => {
517
522
  let tree = parseSnapshot(snapshot);
@@ -1,11 +1,15 @@
1
1
  import { createDebug } from './logger.js';
2
2
  const debugLog = createDebug('explorbot:code-extractor');
3
+ const JS_LANGUAGES = new Set(['', 'js', 'javascript']);
3
4
  export function extractCodeBlocks(aiResponse) {
4
- const codeBlockRegex = /```(?:js|javascript)?\s*\n([\s\S]*?)\n```/g;
5
+ const codeBlockRegex = /```([^\n`]*)\n([\s\S]*?)\n```/g;
5
6
  const codeBlocks = [];
6
7
  let match = null;
7
8
  while ((match = codeBlockRegex.exec(aiResponse))) {
8
- const code = match[1].trim();
9
+ const language = match[1].trim().toLowerCase();
10
+ if (!JS_LANGUAGES.has(language))
11
+ continue;
12
+ const code = match[2].trim();
9
13
  if (!code)
10
14
  continue;
11
15
  try {
@@ -29,6 +29,8 @@ export declare class MarkdownQuery {
29
29
  text(): string;
30
30
  get(): string;
31
31
  toJson(): Record<string, string>[];
32
+ keyValue(): Record<string, string>;
33
+ setKeyValue(key: string, value: string | null): string;
32
34
  replace(content: string): string;
33
35
  replaceEach(replacer: (match: MarkdownQuery, index: number) => string): string;
34
36
  count(): number;
@@ -129,6 +129,12 @@ function matchText(text, matcher) {
129
129
  }
130
130
  return matcher.negated ? !result : result;
131
131
  }
132
+ function entryKey(line) {
133
+ const separator = line.indexOf(':');
134
+ if (separator < 1)
135
+ return null;
136
+ return line.slice(0, separator).trim().toLowerCase();
137
+ }
132
138
  function getTokenText(token) {
133
139
  const t = token;
134
140
  switch (token.type) {
@@ -340,6 +346,39 @@ export class MarkdownQuery {
340
346
  }
341
347
  return results;
342
348
  }
349
+ keyValue() {
350
+ const entries = {};
351
+ for (const range of this.matches) {
352
+ for (const line of getTokenText(range.token).split('\n')) {
353
+ const key = entryKey(line);
354
+ if (!key)
355
+ continue;
356
+ const value = line.slice(line.indexOf(':') + 1).trim();
357
+ if (value)
358
+ entries[key] = value;
359
+ }
360
+ }
361
+ return entries;
362
+ }
363
+ setKeyValue(key, value) {
364
+ return this.replaceEach((match) => {
365
+ const token = match.matches[0].token;
366
+ const lines = getTokenText(token)
367
+ .split('\n')
368
+ .map((line) => line.trim())
369
+ .filter(Boolean);
370
+ const index = lines.findIndex((line) => entryKey(line) === key.toLowerCase());
371
+ if (index < 0 && value)
372
+ lines.push(`${key}: ${value}`);
373
+ if (index >= 0 && value)
374
+ lines[index] = `${key}: ${value}`;
375
+ if (index >= 0 && !value)
376
+ lines.splice(index, 1);
377
+ if (token.type !== 'blockquote')
378
+ return lines.join('\n');
379
+ return lines.map((line) => `> ${line}`).join('\n');
380
+ });
381
+ }
343
382
  replace(content) {
344
383
  return this.replaceEach(() => content);
345
384
  }
@@ -0,0 +1,16 @@
1
+ export declare function inspectList(css: string): ListMeasure | null;
2
+ export declare function restoreScroll({ css, scrollTop, pageScrollY }: ScrollPosition): void;
3
+ export type PaginationStrategy = 'controls' | 'infinite';
4
+ export interface ListMeasure {
5
+ hasPagingControls: boolean;
6
+ isFeed: boolean;
7
+ scrolls: boolean;
8
+ items: number;
9
+ scrollTop: number;
10
+ pageScrollY: number;
11
+ }
12
+ export interface ScrollPosition {
13
+ css: string;
14
+ scrollTop: number;
15
+ pageScrollY: number;
16
+ }
@@ -0,0 +1,20 @@
1
+ export function inspectList(css) {
2
+ const element = document.querySelector(css);
3
+ if (!element)
4
+ return null;
5
+ const rect = element.getBoundingClientRect();
6
+ return {
7
+ hasPagingControls: !!element.querySelector('a[rel="next"], a[rel="prev"]'),
8
+ isFeed: element.matches('[role="feed"]') || !!element.querySelector('[role="feed"]'),
9
+ scrolls: element.scrollHeight > element.clientHeight + 1 || rect.bottom > window.innerHeight,
10
+ items: element.querySelectorAll(':scope > *').length,
11
+ scrollTop: element.scrollTop,
12
+ pageScrollY: window.scrollY,
13
+ };
14
+ }
15
+ export function restoreScroll({ css, scrollTop, pageScrollY }) {
16
+ const element = document.querySelector(css);
17
+ if (element)
18
+ element.scrollTop = scrollTop;
19
+ window.scrollTo(0, pageScrollY);
20
+ }