typebulb 0.44.3 → 0.45.0

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/dist/servers.js CHANGED
@@ -790,9 +790,20 @@ ${s}`}function Hd(t){let e=ur.filter(n=>t[n]).map(n=>i0(n,t[n]));return["---",`f
790
790
  if (lines.length > MAX_LINES) { lines.length = MAX_LINES; lines.push('- \u2026 (truncated)'); }
791
791
  return { lines, targets };
792
792
  };
793
+ // The scrolling element's client box is the usable area minus scrollbars \u2014 the only basis on
794
+ // which "content \u2264 viewport" is the same verdict the scrollbar's presence gives the user.
795
+ const pageGeometry = () => {
796
+ const de = document.scrollingElement || document.documentElement;
797
+ const over = [];
798
+ if (de.scrollHeight > de.clientHeight) over.push('vertically by ' + (de.scrollHeight - de.clientHeight) + 'px');
799
+ if (de.scrollWidth > de.clientWidth) over.push('horizontally by ' + (de.scrollWidth - de.clientWidth) + 'px');
800
+ return '- page: viewport ' + de.clientWidth + '\xD7' + de.clientHeight
801
+ + ', content ' + de.scrollWidth + '\xD7' + de.scrollHeight
802
+ + ' \u2014 ' + (over.length ? 'overflows ' + over.join(', ') : 'fits');
803
+ };
793
804
  const snapshot = () => {
794
805
  const { lines } = collectOutline();
795
- return lines.length ? lines.join('\\n') : '(empty page)';
806
+ return pageGeometry() + '\\n' + (lines.length ? lines.join('\\n') : '(empty page)');
796
807
  };
797
808
 
798
809
  // tb:click / tb:set (TB-Interrogation-Actuation.md). A target is role + name exactly as the
@@ -864,6 +875,20 @@ ${s}`}function Hd(t){let e=ur.filter(n=>t[n]).map(n=>i0(n,t[n]));return["---",`f
864
875
  }
865
876
  return postFrameSnapshot();
866
877
  };
878
+ // tb:rect \u2014 a read in the actuation grammar: the named control's viewport-relative rect plus the
879
+ // viewport itself, so the reply is self-interpreting. No scrollIntoView \u2014 a read disturbs nothing.
880
+ const readRect = (rest) => {
881
+ const t = parseActuation('tb:rect <role> "<name>"', rest);
882
+ if (t.rest) throw new Error('usage: tb:rect <role> "<name>"');
883
+ const el = resolveTarget(t.role, t.name);
884
+ const r = el.getBoundingClientRect();
885
+ const de = document.scrollingElement || document.documentElement;
886
+ return {
887
+ x: Math.round(r.x), y: Math.round(r.y),
888
+ width: Math.round(r.width), height: Math.round(r.height),
889
+ viewport: { width: de.clientWidth, height: de.clientHeight }
890
+ };
891
+ };
867
892
  const actSet = (rest) => {
868
893
  const t = parseActuation('tb:set <role> "<name>" = <value>', rest);
869
894
  const vm = /^=\\s*([\\s\\S]*)$/.exec(t.rest.trim());
@@ -920,7 +945,8 @@ ${zA}
920
945
  if (p === 'tb:snapshot') return snapshot();
921
946
  if (p === 'tb:click' || p.indexOf('tb:click ') === 0) return actClick(p.slice(9));
922
947
  if (p === 'tb:set' || p.indexOf('tb:set ') === 0) return actSet(p.slice(7));
923
- throw new Error('unknown reserved message: ' + p + ' (known: tb:snapshot, tb:click, tb:set)');
948
+ if (p === 'tb:rect' || p.indexOf('tb:rect ') === 0) return readRect(p.slice(8));
949
+ throw new Error('unknown reserved message: ' + p + ' (known: tb:snapshot, tb:rect, tb:click, tb:set)');
924
950
  };
925
951
  const value = parseMsg(env.payload);
926
952
  const calls = typeof env.payload === 'string' && env.payload.indexOf('tb:') === 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.44.3",
3
+ "version": "0.45.0",
4
4
  "description": "Typebulb CLI to run single-file markdown apps called bulbs, either as standalone web apps or embedded in agent responses.",
5
5
  "keywords": [
6
6
  "bulb",