codeam-cli 2.76.35 → 2.76.37

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/index.js CHANGED
@@ -3458,6 +3458,724 @@ CRITICAL \u2014 setup_commands:
3458
3458
  OUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.
3459
3459
  `.trim();
3460
3460
 
3461
+ // ../../packages/shared/src/point-picker/script.ts
3462
+ var POINT_TEXT_MAX = 120;
3463
+ var POINT_HTML_MAX = 600;
3464
+ var DEFAULT_ACCENT = "#7C5CFF";
3465
+ var HEX = /^#[0-9A-Fa-f]{6}$/;
3466
+ var IDENT = /^[A-Za-z_$][\w$]*$/;
3467
+ function js(v) {
3468
+ return JSON.stringify(v).replace(/</g, "\\u003c");
3469
+ }
3470
+ function pointPickerScript(opts) {
3471
+ const multi = opts.mode === "multi";
3472
+ const maxMarks = opts.maxMarks ?? 4;
3473
+ const accent = opts.accent ?? DEFAULT_ACCENT;
3474
+ if (opts.channelField !== "channel" && opts.channelField !== "source") {
3475
+ throw new Error(`pointPickerScript: bad channelField ${String(opts.channelField)}`);
3476
+ }
3477
+ if (!HEX.test(accent))
3478
+ throw new Error(`pointPickerScript: accent must be #RRGGBB, got ${accent}`);
3479
+ if (!Number.isInteger(maxMarks) || maxMarks < 1) {
3480
+ throw new Error(`pointPickerScript: maxMarks must be a positive integer, got ${maxMarks}`);
3481
+ }
3482
+ if (opts.globalName !== void 0 && !IDENT.test(opts.globalName)) {
3483
+ throw new Error(`pointPickerScript: globalName must be an identifier, got ${opts.globalName}`);
3484
+ }
3485
+ return `(function () {
3486
+ 'use strict';
3487
+ var W = window, D = document;
3488
+ var CH = ${js(opts.channel)};
3489
+ var FIELD = ${js(opts.channelField)};
3490
+ var ALLOWED = ${js(opts.allowedParents)};
3491
+ var MULTI = ${multi}, MAX_MARKS = ${maxMarks}, AGENT = ${!!opts.agentHighlights}, REACT_SOURCE = ${!!opts.reactSource};
3492
+ var GLOBAL = ${js(opts.globalName ?? null)};
3493
+ var DEFAULT_ACCENT = ${js(accent)};
3494
+ var GUARD = '__pointPicker:' + CH;
3495
+ if (W[GUARD]) return;
3496
+ try { Object.defineProperty(W, GUARD, { value: true }); } catch (e) { return; }
3497
+ try {
3498
+ var TEXT_MAX = ${POINT_TEXT_MAX}, HTML_MAX = ${POINT_HTML_MAX}, ATTR_MAX = 60;
3499
+ var ACCENT_RE = /^#[0-9A-Fa-f]{6}$/;
3500
+ var AGENT_ACCENT = '#22d3ee';
3501
+ var EASE = 'cubic-bezier(.2,.8,.2,1)';
3502
+ var CHIP_FONT = 'italic 500 13px/1.3 Georgia,"Times New Roman",serif';
3503
+ var CONTROLS = { BUTTON: 1, A: 1, INPUT: 1, SELECT: 1, TEXTAREA: 1, LABEL: 1, SUMMARY: 1 };
3504
+ var ROLES = { button: 1, link: 1, tab: 1, checkbox: 1, switch: 1, menuitem: 1, option: 1, radio: 1, slider: 1 };
3505
+ var VOID = { AREA: 1, BR: 1, COL: 1, EMBED: 1, HR: 1, IMG: 1, INPUT: 1, LINK: 1, META: 1, SOURCE: 1, TRACK: 1, WBR: 1 };
3506
+ var GRAIN = "url(\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .08 0 0 0 0 .08 0 0 0 0 .09 0 0 0 .12 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\\")";
3507
+
3508
+ var on = false, driver = null, accent = DEFAULT_ACCENT;
3509
+ var host = null, veil = null, ring = null, chip = null, style = null, leaving = null;
3510
+ var current = null, down = null, tapped = false, bound = [], swallow = null;
3511
+ // Multi mode: the pinned marks, drawn in the page and anchored to the document.
3512
+ // Mark ids carry a per-load prefix: after a reload \`seq\` restarts, and the
3513
+ // app may still hold the previous page's p\u2026-1.
3514
+ var picked = [], seq = 0, marksHost = null, marksRoot = null;
3515
+ var LOAD = (Math.random().toString(36).slice(2) + '0000').slice(0, 4);
3516
+ // The agent's highlights: separate from the person's marks, never numbered.
3517
+ var agentMarks = [], agentHost = null, agentRoot = null, agentLayer = null, agentCursor = null, agentListening = false;
3518
+
3519
+ // Inside a React Native WebView the document is TOP-LEVEL (window.parent ===
3520
+ // window), so the only way out is the bridge RN injects. It carries STRINGS.
3521
+ function rnBridge() {
3522
+ if (!GLOBAL) return null;
3523
+ var rn = W.ReactNativeWebView;
3524
+ return rn && typeof rn.postMessage === 'function' ? rn : null;
3525
+ }
3526
+
3527
+ function send(type, extra) {
3528
+ if (!driver) return;
3529
+ var msg = {};
3530
+ msg[FIELD] = CH;
3531
+ msg.type = type;
3532
+ if (extra) for (var k in extra) msg[k] = extra[k];
3533
+ var rn = rnBridge();
3534
+ if (rn) {
3535
+ try { rn.postMessage(JSON.stringify(msg)); } catch (e) {}
3536
+ return;
3537
+ }
3538
+ if (W.parent === W) return;
3539
+ try { W.parent.postMessage(msg, driver); } catch (e) {}
3540
+ }
3541
+
3542
+ function clip(s, max) { return s.length > max ? s.slice(0, max - 1) + '\\u2026' : s; }
3543
+ function squash(s) { return String(s == null ? '' : s).replace(/\\s+/g, ' ').trim(); }
3544
+ function attr(el, n) { var v = el.getAttribute ? el.getAttribute(n) : null; return v == null ? '' : String(v); }
3545
+ function tagOf(el) { return String(el.tagName || '').toLowerCase(); }
3546
+ function reduced() {
3547
+ try { return !!(W.matchMedia && W.matchMedia('(prefers-reduced-motion: reduce)').matches); } catch (e) { return false; }
3548
+ }
3549
+ function drop(node) { if (node && node.parentNode) node.parentNode.removeChild(node); }
3550
+ function shadowOf(el) { return el.attachShadow ? el.attachShadow({ mode: 'closed' }) : el; }
3551
+ function clear(node) { while (node && node.childNodes && node.childNodes.length) node.removeChild(node.childNodes[0]); }
3552
+
3553
+ // A tap lands on the innermost node (the <span> in a button, the <path> in
3554
+ // an icon); the person means the control around it.
3555
+ function target(el) {
3556
+ var n = el;
3557
+ for (var depth = 0; n && n !== D.body && n !== D.documentElement && depth < 6; depth++) {
3558
+ if (CONTROLS[String(n.tagName).toUpperCase()] || ROLES[attr(n, 'role')]) return n;
3559
+ n = n.parentElement;
3560
+ }
3561
+ n = el;
3562
+ while (n.ownerSVGElement) n = n.ownerSVGElement;
3563
+ return n;
3564
+ }
3565
+
3566
+ function pickable(el) {
3567
+ return !!el && el.nodeType === 1 && el !== D.documentElement && el !== D.body &&
3568
+ el !== host && el !== marksHost && el !== agentHost;
3569
+ }
3570
+
3571
+ // CSS.escape where the browser has it; else the same algorithm (CSSOM).
3572
+ // Without it a Tailwind class (\`md:flex\`, \`w-1/2\`) makes an invalid selector.
3573
+ function cssEsc(v) {
3574
+ v = String(v);
3575
+ try { if (W.CSS && typeof W.CSS.escape === 'function') return W.CSS.escape(v); } catch (e) {}
3576
+ var out = '';
3577
+ for (var i = 0; i < v.length; i++) {
3578
+ var ch = v.charAt(i), code = v.charCodeAt(i);
3579
+ if (code === 0) out += '\\uFFFD';
3580
+ else if ((code >= 1 && code <= 31) || code === 127 || (i === 0 && code >= 48 && code <= 57) ||
3581
+ (i === 1 && code >= 48 && code <= 57 && v.charAt(0) === '-')) out += '\\\\' + code.toString(16) + ' ';
3582
+ else if (i === 0 && ch === '-' && v.length === 1) out += '\\\\-';
3583
+ else if (code >= 128 || ch === '-' || ch === '_' || /[0-9A-Za-z]/.test(ch)) out += ch;
3584
+ else out += '\\\\' + ch;
3585
+ }
3586
+ return out;
3587
+ }
3588
+
3589
+ // One step of the path. \`lean\` (tag + position only) is the fallback for
3590
+ // a step that alone would not fit the budget.
3591
+ function step(el, lean) {
3592
+ var t = tagOf(el);
3593
+ if (el.id && !lean) return t + '#' + cssEsc(el.id);
3594
+ var c = lean ? [] : squash(attr(el, 'class')).split(' ').filter(Boolean).slice(0, 2);
3595
+ var s = t;
3596
+ for (var k = 0; k < c.length; k++) s += '.' + cssEsc(c[k]);
3597
+ var p = el.parentElement;
3598
+ if (p && p.children) {
3599
+ var same = 0, index = 0;
3600
+ for (var i = 0; i < p.children.length; i++) {
3601
+ if (p.children[i].tagName === el.tagName) {
3602
+ same++;
3603
+ if (p.children[i] === el) index = same;
3604
+ }
3605
+ }
3606
+ if (same > 1) s += ':nth-of-type(' + index + ')';
3607
+ }
3608
+ return s;
3609
+ }
3610
+
3611
+ // Never cut with an ellipsis (that would be no selector at all): drop the
3612
+ // outermost ancestors until the path fits, so it always matches the element.
3613
+ function selectorFor(el) {
3614
+ var parts = [], n = el;
3615
+ while (n && n.nodeType === 1 && n !== D.body && n !== D.documentElement && parts.length < 4) {
3616
+ parts.unshift(step(n));
3617
+ if (n.id) break;
3618
+ n = n.parentElement;
3619
+ }
3620
+ while (parts.length > 1 && parts.join(' > ').length > 200) parts.shift();
3621
+ if (parts[0].length > 200) parts[0] = step(el, true);
3622
+ return parts.join(' > ');
3623
+ }
3624
+
3625
+ function textOf(el) {
3626
+ return clip(squash(attr(el, 'aria-label') || el.textContent || attr(el, 'placeholder') || attr(el, 'alt') || attr(el, 'title')), TEXT_MAX);
3627
+ }
3628
+
3629
+ function esc(s) { return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;'); }
3630
+
3631
+ // The element's markup within a budget: attributes trimmed, never more than
3632
+ // HTML_MAX characters walked, so a huge container costs nothing.
3633
+ function htmlOf(el) {
3634
+ var out = [], left = HTML_MAX + 1;
3635
+ function put(s) {
3636
+ if (left <= 0) return;
3637
+ out.push(s.length > left ? s.slice(0, left) : s);
3638
+ left -= s.length;
3639
+ }
3640
+ function walk(n, depth) {
3641
+ if (left <= 0) return;
3642
+ if (n.nodeType === 3) {
3643
+ var text = String(n.nodeValue == null ? '' : n.nodeValue).replace(/\\s+/g, ' ');
3644
+ if (text.trim()) put(esc(text));
3645
+ return;
3646
+ }
3647
+ if (n.nodeType !== 1) return;
3648
+ var t = tagOf(n);
3649
+ put('<' + t);
3650
+ var a = n.attributes || [];
3651
+ for (var i = 0; i < a.length; i++) put(' ' + a[i].name + '="' + esc(clip(String(a[i].value), ATTR_MAX)) + '"');
3652
+ put('>');
3653
+ if (VOID[t.toUpperCase()]) return;
3654
+ if (t === 'script' || t === 'style') put('\\u2026');
3655
+ else if (depth >= 4) { if (n.childNodes && n.childNodes.length) put('\\u2026'); }
3656
+ else for (var c = 0; n.childNodes && c < n.childNodes.length && left > 0; c++) walk(n.childNodes[c], depth + 1);
3657
+ put('</' + t + '>');
3658
+ }
3659
+ walk(el, 0);
3660
+ var s = out.join('');
3661
+ return s.length > HTML_MAX ? s.slice(0, HTML_MAX - 1) + '\\u2026' : s;
3662
+ }
3663
+
3664
+ // The React component's file and line, when a dev build exposes them: the
3665
+ // agent gets "components/buy-button.tsx:42" instead of a CSS path.
3666
+ function reactSourceOf(el) {
3667
+ try {
3668
+ for (var key in el) {
3669
+ if (key.indexOf('__reactFiber$') !== 0) continue;
3670
+ var fiber = el[key];
3671
+ while (fiber) {
3672
+ var src = fiber._debugSource;
3673
+ if (src && src.fileName) return { file: String(src.fileName), line: Number(src.lineNumber) || null };
3674
+ fiber = fiber.return;
3675
+ }
3676
+ }
3677
+ } catch (e) {}
3678
+ return null;
3679
+ }
3680
+
3681
+ function describe(el) {
3682
+ var r = el.getBoundingClientRect();
3683
+ var out = {
3684
+ tag: tagOf(el),
3685
+ id: el.id ? clip(String(el.id), 100) : null,
3686
+ classes: clip(squash(attr(el, 'class')), 200),
3687
+ selector: selectorFor(el),
3688
+ text: textOf(el),
3689
+ html: htmlOf(el),
3690
+ rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) }
3691
+ };
3692
+ if (MULTI) out.viewport = { w: W.innerWidth, h: W.innerHeight };
3693
+ if (REACT_SOURCE) out.source = reactSourceOf(el);
3694
+ return out;
3695
+ }
3696
+
3697
+ function kindOf(el) {
3698
+ var t = tagOf(el), role = attr(el, 'role'), type = attr(el, 'type');
3699
+ if (t === 'button' || role === 'button' || (t === 'input' && /^(button|submit|reset)$/.test(type))) return 'button';
3700
+ if (t === 'a' || role === 'link') return 'link';
3701
+ if (t === 'input' || t === 'textarea' || t === 'select') return 'field';
3702
+ if (t === 'img' || t === 'svg' || t === 'picture' || t === 'canvas') return 'image';
3703
+ if (/^h[1-6]$/.test(t)) return 'heading';
3704
+ return t;
3705
+ }
3706
+
3707
+ function label(el) {
3708
+ var text = squash(textOf(el));
3709
+ var kind = kindOf(el);
3710
+ return text ? '\\u201c' + clip(text, 28) + '\\u201d ' + kind : kind;
3711
+ }
3712
+
3713
+ function cursor() {
3714
+ var svg = "<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='9.5' fill='" + accent + "' fill-opacity='.14' stroke='" + accent + "' stroke-width='2'/><path d='M16 1v7M16 24v7M1 16h7M24 16h7' stroke='" + accent + "' stroke-width='1.6' stroke-linecap='round'/><circle cx='16' cy='16' r='1.6' fill='" + accent + "'/></svg>";
3715
+ return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '") 16 16, crosshair';
3716
+ }
3717
+
3718
+ function canHole() {
3719
+ try { return !!(W.CSS && W.CSS.supports && W.CSS.supports('clip-path', 'path(evenodd, "M0 0H1V1Z")')); } catch (e) { return false; }
3720
+ }
3721
+
3722
+ // The veil covers the app except a rounded window around the element.
3723
+ function holePath(r) {
3724
+ var w = Math.round(W.innerWidth), h = Math.round(W.innerHeight), p = 6;
3725
+ var x = Math.round(r.left - p), y = Math.round(r.top - p);
3726
+ var rw = Math.round(r.width + 2 * p), rh = Math.round(r.height + 2 * p);
3727
+ var k = Math.max(0, Math.min(12, Math.floor(rw / 2), Math.floor(rh / 2)));
3728
+ var arc = 'A' + k + ' ' + k + ' 0 0 1 ';
3729
+ return 'path(evenodd, "M0 0H' + w + 'V' + h + 'H0Z' +
3730
+ 'M' + (x + k) + ' ' + y + 'H' + (x + rw - k) + arc + (x + rw) + ' ' + (y + k) +
3731
+ 'V' + (y + rh - k) + arc + (x + rw - k) + ' ' + (y + rh) +
3732
+ 'H' + (x + k) + arc + x + ' ' + (y + rh - k) +
3733
+ 'V' + (y + k) + arc + (x + k) + ' ' + y + 'Z")';
3734
+ }
3735
+
3736
+ // The Remix ring and chip, shared by the pointer, the marks and the agent.
3737
+ function ringCss(color) {
3738
+ return 'box-sizing:border-box;border:2px solid ' + color + ';border-radius:12px;box-shadow:0 0 0 5px ' + color + '29';
3739
+ }
3740
+ function chipCss(color) {
3741
+ return 'white-space:nowrap;padding:4px 10px;border-radius:999px;background:#141416;color:#f6f3ee;font:' + CHIP_FONT +
3742
+ ';box-shadow:0 0 0 1px ' + color;
3743
+ }
3744
+
3745
+ // A host for our nodes: a custom element, max z-index, its own closed
3746
+ // shadow root so the page's CSS can't restyle (or hide) what we draw. Last
3747
+ // child of <html>, so at an equal z-index it still paints on top.
3748
+ function makeHost(role, position) {
3749
+ var el = D.createElement('remix-point');
3750
+ if (role === 'point') el.setAttribute('data-remix-point', '');
3751
+ el.setAttribute('data-codeam', role);
3752
+ el.style.cssText = 'all:initial;position:' + position + ';top:0;left:0;width:0;height:0;pointer-events:none;z-index:2147483647';
3753
+ return el;
3754
+ }
3755
+
3756
+ function build() {
3757
+ if (leaving && leaving.parentNode) leaving.parentNode.removeChild(leaving);
3758
+ leaving = null;
3759
+ var motion = reduced() ? 'none' : 'transform .16s ' + EASE + ', width .16s ' + EASE + ', height .16s ' + EASE + ', opacity .16s';
3760
+ host = makeHost('point', 'fixed');
3761
+ var root = shadowOf(host);
3762
+ veil = D.createElement('div');
3763
+ veil.setAttribute('data-codeam', 'veil');
3764
+ veil.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;pointer-events:none;opacity:0;' +
3765
+ 'background:rgba(246,243,238,.46) ' + GRAIN + ';-webkit-backdrop-filter:grayscale(.7);backdrop-filter:grayscale(.7);' +
3766
+ 'transition:' + (reduced() ? 'none' : 'opacity .2s');
3767
+ ring = D.createElement('div');
3768
+ ring.setAttribute('data-codeam', 'ring');
3769
+ ring.style.cssText = 'position:fixed;top:0;left:0;width:0;height:0;pointer-events:none;opacity:0;' +
3770
+ ringCss(accent) + ';transition:' + motion;
3771
+ chip = D.createElement('div');
3772
+ chip.setAttribute('data-codeam', 'chip');
3773
+ chip.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;opacity:0;' + chipCss(accent) + ';transition:' + motion;
3774
+ root.appendChild(veil);
3775
+ root.appendChild(ring);
3776
+ root.appendChild(chip);
3777
+ D.documentElement.appendChild(host);
3778
+ style = D.createElement('style');
3779
+ style.textContent = 'html[data-remix-pointing],html[data-remix-pointing] *{cursor:' + cursor() + ' !important;' +
3780
+ 'user-select:none !important;-webkit-user-select:none !important;-webkit-touch-callout:none !important}';
3781
+ (D.head || D.documentElement).appendChild(style);
3782
+ D.documentElement.setAttribute('data-remix-pointing', '');
3783
+ }
3784
+
3785
+ function paint(el) {
3786
+ current = el;
3787
+ var r = el.getBoundingClientRect();
3788
+ ring.style.transform = 'translate(' + Math.round(r.left - 4) + 'px,' + Math.round(r.top - 4) + 'px)';
3789
+ ring.style.width = Math.round(r.width + 8) + 'px';
3790
+ ring.style.height = Math.round(r.height + 8) + 'px';
3791
+ ring.style.opacity = '1';
3792
+ if (canHole()) {
3793
+ veil.style.clipPath = holePath(r);
3794
+ veil.style.opacity = '1';
3795
+ }
3796
+ chip.textContent = label(el);
3797
+ var top = r.top >= 34 ? r.top - 32 : r.top + r.height + 8;
3798
+ var left = Math.max(8, Math.min(r.left, W.innerWidth - 200));
3799
+ chip.style.transform = 'translate(' + Math.round(left) + 'px,' + Math.round(top) + 'px)';
3800
+ chip.style.opacity = '1';
3801
+ }
3802
+
3803
+ // Paint, and in multi mode tell the parent what is under the finger.
3804
+ function hoverTo(el) {
3805
+ var changed = el !== current;
3806
+ paint(el);
3807
+ if (changed && MULTI) send('hover', { element: describe(el) });
3808
+ }
3809
+
3810
+ // While pointing, the app never sees the gesture: no click, no focus, no
3811
+ // drag. Touch scrolling still works (its default is left alone).
3812
+ function block(e) {
3813
+ if (e.stopImmediatePropagation) e.stopImmediatePropagation();
3814
+ if (e.cancelable && e.type !== 'touchstart' && e.type !== 'touchmove') e.preventDefault();
3815
+ }
3816
+
3817
+ // What is under the pointer. Hit-testing first (a touch keeps targeting
3818
+ // the element it went down on); the event target where there is none.
3819
+ function at(e) {
3820
+ var el = null;
3821
+ if (D.elementFromPoint) {
3822
+ try { el = D.elementFromPoint(e.clientX, e.clientY); } catch (x) { el = null; }
3823
+ }
3824
+ if (!el && e.target && e.target.nodeType === 1) el = e.target;
3825
+ return pickable(el) ? target(el) : null;
3826
+ }
3827
+
3828
+ function onDown(e) {
3829
+ block(e);
3830
+ down = { id: e.pointerId };
3831
+ tapped = true;
3832
+ var el = at(e);
3833
+ if (el) hoverTo(el);
3834
+ }
3835
+
3836
+ function onMove(e) {
3837
+ block(e);
3838
+ var el = at(e);
3839
+ if (el && el !== current) hoverTo(el);
3840
+ }
3841
+
3842
+ // Browsers without pointer events (old WebViews) only send mouse events.
3843
+ // Never blocked: the app keeps its own mousemove, as it always did.
3844
+ function onMouseMove(e) {
3845
+ var el = at(e);
3846
+ if (el && el !== current) hoverTo(el);
3847
+ }
3848
+
3849
+ function onUp(e) {
3850
+ block(e);
3851
+ var d = down;
3852
+ down = null;
3853
+ if (!d || d.id !== e.pointerId || e.button > 0) return;
3854
+ var el = at(e) || current;
3855
+ if (el) {
3856
+ pick(el);
3857
+ armClickSwallow();
3858
+ }
3859
+ }
3860
+
3861
+ // The click that follows a tap was already picked on pointerup; a click
3862
+ // with no pointer gesture before it (an old WebView) is the pick itself.
3863
+ function onClick(e) {
3864
+ block(e);
3865
+ if (tapped) { tapped = false; return; }
3866
+ var el = at(e);
3867
+ if (el) pick(el);
3868
+ }
3869
+
3870
+ // The browser fires a click after the pointerup that picked. Once pointing
3871
+ // is off (single mode, or the parent turned it off in between) nothing of
3872
+ // ours would catch it, and a pointed-at link would navigate. One shot:
3873
+ // gone on the next click, or after 400 ms when no click comes.
3874
+ function armClickSwallow() {
3875
+ disarmClickSwallow();
3876
+ var fn = function (e) {
3877
+ block(e);
3878
+ disarmClickSwallow();
3879
+ };
3880
+ swallow = fn;
3881
+ W.addEventListener('click', fn, { capture: true, passive: false });
3882
+ W.setTimeout(function () { if (swallow === fn) disarmClickSwallow(); }, 400);
3883
+ }
3884
+
3885
+ function disarmClickSwallow() {
3886
+ if (!swallow) return;
3887
+ W.removeEventListener('click', swallow, { capture: true });
3888
+ swallow = null;
3889
+ }
3890
+
3891
+ // The browser took the touch over to scroll: that was not a tap.
3892
+ function onCancel(e) {
3893
+ block(e);
3894
+ down = null;
3895
+ tapped = false;
3896
+ }
3897
+
3898
+ function onKey(e) {
3899
+ block(e);
3900
+ // In multi mode the parent owns the toggle: Escape ends nothing it can't see.
3901
+ if (!MULTI && e.type === 'keydown' && (e.key === 'Escape' || e.key === 'Esc')) {
3902
+ send('cancel');
3903
+ off(false);
3904
+ }
3905
+ }
3906
+
3907
+ function onScroll() {
3908
+ if (current) paint(current);
3909
+ if (picked.length) drawMarks();
3910
+ }
3911
+
3912
+ var HANDLERS = [
3913
+ ['pointerdown', onDown], ['pointermove', onMove], ['pointerup', onUp], ['pointercancel', onCancel],
3914
+ ['mousedown', block], ['mouseup', block], ['mousemove', onMouseMove], ['click', onClick], ['dblclick', block], ['auxclick', block],
3915
+ ['contextmenu', block], ['touchstart', block], ['touchmove', block], ['touchend', block],
3916
+ ['submit', block], ['keydown', onKey], ['keyup', block], ['keypress', block]
3917
+ ];
3918
+
3919
+ function pick(el) {
3920
+ var element = describe(el);
3921
+ if (!MULTI) {
3922
+ off(true);
3923
+ send('pick', { element: element });
3924
+ return;
3925
+ }
3926
+ // Past the cap the pick still goes up (the app says "4 marks max") but
3927
+ // leaves nothing in the page the app would never be able to remove.
3928
+ if (picked.length < MAX_MARKS) {
3929
+ var id = 'p' + LOAD + '-' + (++seq);
3930
+ picked.push({ id: id, el: el });
3931
+ element.markId = id;
3932
+ drawMarks(id);
3933
+ }
3934
+ send('pick', { element: element });
3935
+ }
3936
+
3937
+ // The pinned marks: Remix rings with a numbered chip, anchored to the
3938
+ // DOCUMENT (absolute + scroll) so they travel with the content.
3939
+ function drawMarks(fresh) {
3940
+ if (!picked.length) {
3941
+ drop(marksHost);
3942
+ marksHost = marksRoot = null;
3943
+ return;
3944
+ }
3945
+ if (!marksHost || !marksHost.parentNode) {
3946
+ marksHost = makeHost('marks', 'absolute');
3947
+ marksRoot = shadowOf(marksHost);
3948
+ D.documentElement.appendChild(marksHost);
3949
+ }
3950
+ clear(marksRoot);
3951
+ var calm = reduced();
3952
+ if (!calm) {
3953
+ var keys = D.createElement('style');
3954
+ keys.textContent = '@keyframes pp-pin{from{opacity:0;transform:scale(1.04)}to{opacity:1;transform:scale(1)}}';
3955
+ marksRoot.appendChild(keys);
3956
+ }
3957
+ var sx = W.scrollX || W.pageXOffset || 0, sy = W.scrollY || W.pageYOffset || 0;
3958
+ for (var i = 0; i < picked.length; i++) {
3959
+ var r = picked[i].el.getBoundingClientRect();
3960
+ var box = D.createElement('div');
3961
+ box.setAttribute('data-codeam', 'mark');
3962
+ box.style.cssText = 'position:absolute;pointer-events:none;' + ringCss(accent) +
3963
+ ';left:' + Math.round(r.left + sx - 4) + 'px;top:' + Math.round(r.top + sy - 4) + 'px' +
3964
+ ';width:' + Math.round(r.width + 8) + 'px;height:' + Math.round(r.height + 8) + 'px' +
3965
+ (!calm && picked[i].id === fresh ? ';animation:pp-pin .32s ' + EASE : '');
3966
+ var badge = D.createElement('div');
3967
+ badge.setAttribute('data-codeam', 'mark-badge');
3968
+ badge.style.cssText = 'position:absolute;left:-11px;top:-11px;width:22px;height:22px;border-radius:11px;' +
3969
+ 'background:#141416;color:#f6f3ee;font:italic 600 12px/22px Georgia,"Times New Roman",serif;text-align:center;' +
3970
+ 'box-shadow:0 0 0 1px ' + accent + ';pointer-events:none';
3971
+ badge.textContent = String(i + 1);
3972
+ box.appendChild(badge);
3973
+ marksRoot.appendChild(box);
3974
+ }
3975
+ }
3976
+
3977
+ // The parent sends the ids still alive, in order: a removed chip removes
3978
+ // its mark, and the rest renumber (what the person writes, "1 is off",
3979
+ // refers to these numbers).
3980
+ function syncMarks(ids) {
3981
+ var byId = {};
3982
+ for (var i = 0; i < picked.length; i++) byId[picked[i].id] = picked[i];
3983
+ var next = [];
3984
+ for (var j = 0; j < ids.length; j++) if (byId[ids[j]]) next.push(byId[ids[j]]);
3985
+ picked = next;
3986
+ drawMarks();
3987
+ }
3988
+
3989
+ // The agent pointing (highlight_element): a cursor travels to the element,
3990
+ // centres it, and leaves a cyan Remix ring with its label. Independent of
3991
+ // pointing mode, anchored to the document like the marks.
3992
+ function ensureAgent() {
3993
+ if (agentHost && agentHost.parentNode) return;
3994
+ agentHost = makeHost('agent', 'absolute');
3995
+ agentRoot = shadowOf(agentHost);
3996
+ var keys = D.createElement('style');
3997
+ keys.textContent =
3998
+ '@keyframes pp-agent-pulse{0%{box-shadow:0 0 0 0 rgba(34,211,238,.55)}70%{box-shadow:0 0 0 10px rgba(34,211,238,0)}100%{box-shadow:0 0 0 5px rgba(34,211,238,.16)}}' +
3999
+ '@keyframes pp-agent-in{from{opacity:0;transform:scale(1.04)}to{opacity:1;transform:scale(1)}}';
4000
+ agentRoot.appendChild(keys);
4001
+ agentLayer = D.createElement('div');
4002
+ agentRoot.appendChild(agentLayer);
4003
+ D.documentElement.appendChild(agentHost);
4004
+ }
4005
+
4006
+ function ensureAgentCursor() {
4007
+ if (agentCursor && agentCursor.parentNode) return agentCursor;
4008
+ agentCursor = D.createElement('div');
4009
+ agentCursor.setAttribute('data-codeam', 'agent-cursor');
4010
+ agentCursor.style.cssText = 'position:fixed;pointer-events:none;opacity:0;' +
4011
+ 'left:' + Math.round(W.innerWidth / 2) + 'px;top:' + Math.round(W.innerHeight - 40) + 'px;' +
4012
+ 'transition:' + (reduced() ? 'none' : 'left .6s cubic-bezier(.22,1,.36,1),top .6s cubic-bezier(.22,1,.36,1),opacity .3s');
4013
+ agentCursor.innerHTML =
4014
+ '<svg width="22" height="22" viewBox="0 0 24 24" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))">' +
4015
+ '<path d="M4 2l15 8.5-6.6 1.6L9 18.5z" fill="' + AGENT_ACCENT + '" stroke="#141416" stroke-width="1.2"/></svg>' +
4016
+ '<div style="margin:2px 0 0 14px;display:inline-block;' + chipCss(AGENT_ACCENT) + ';padding:2px 8px;font-size:11px">Agent</div>';
4017
+ agentRoot.appendChild(agentCursor);
4018
+ return agentCursor;
4019
+ }
4020
+
4021
+ function drawAgentMarks() {
4022
+ if (!agentLayer) return;
4023
+ clear(agentLayer);
4024
+ var calm = reduced();
4025
+ var sx = W.scrollX || W.pageXOffset || 0, sy = W.scrollY || W.pageYOffset || 0;
4026
+ for (var i = 0; i < agentMarks.length; i++) {
4027
+ var m = agentMarks[i];
4028
+ if (m.el.isConnected === false) continue;
4029
+ var r = m.el.getBoundingClientRect();
4030
+ var box = D.createElement('div');
4031
+ box.setAttribute('data-codeam', 'agent-mark');
4032
+ box.style.cssText = 'position:absolute;pointer-events:none;' + ringCss(AGENT_ACCENT) +
4033
+ ';left:' + Math.round(r.left + sx - 4) + 'px;top:' + Math.round(r.top + sy - 4) + 'px' +
4034
+ ';width:' + Math.round(r.width + 8) + 'px;height:' + Math.round(r.height + 8) + 'px' +
4035
+ (calm ? '' : ';animation:pp-agent-in .25s ' + EASE + ',pp-agent-pulse 1.6s ease-out 3');
4036
+ if (m.label) {
4037
+ var tag = D.createElement('div');
4038
+ tag.setAttribute('data-codeam', 'agent-mark-label');
4039
+ // Above the element when it fits, else below \u2014 same rule as the chip.
4040
+ tag.style.cssText = 'position:absolute;left:0;' + (r.top >= 34 ? 'top:-30px' : 'top:' + Math.round(r.height + 12) + 'px') +
4041
+ ';pointer-events:none;' + chipCss(AGENT_ACCENT) + ';max-width:260px;overflow:hidden;text-overflow:ellipsis';
4042
+ tag.textContent = m.label;
4043
+ box.appendChild(tag);
4044
+ }
4045
+ agentLayer.appendChild(box);
4046
+ }
4047
+ }
4048
+
4049
+ function listenAgentLayout() {
4050
+ if (agentListening) return;
4051
+ agentListening = true;
4052
+ W.addEventListener('scroll', drawAgentMarks, true);
4053
+ W.addEventListener('resize', drawAgentMarks);
4054
+ }
4055
+
4056
+ function agentHighlight(selector, text) {
4057
+ var el = null;
4058
+ try { el = D.querySelector(String(selector)); } catch (e) { el = null; }
4059
+ if (!el || !el.getBoundingClientRect) return false;
4060
+ ensureAgent();
4061
+ listenAgentLayout();
4062
+ var calm = reduced();
4063
+ try { el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: calm ? 'auto' : 'smooth' }); } catch (e) {}
4064
+ var pointer = ensureAgentCursor();
4065
+ var owner = agentHost;
4066
+ // After the smooth scroll the cursor travels to the element and, on
4067
+ // arrival, the ring appears: read as "the agent is pointing at this".
4068
+ W.setTimeout(function () {
4069
+ if (agentHost !== owner) return;
4070
+ var r = el.getBoundingClientRect();
4071
+ pointer.style.opacity = '1';
4072
+ pointer.style.left = Math.round(r.left + Math.min(r.width / 2, 40)) + 'px';
4073
+ pointer.style.top = Math.round(r.top + Math.min(r.height / 2, 24)) + 'px';
4074
+ W.setTimeout(function () {
4075
+ if (agentHost !== owner) return;
4076
+ agentMarks.push({ el: el, label: text ? String(text).slice(0, 80) : '' });
4077
+ drawAgentMarks();
4078
+ }, 620);
4079
+ }, 380);
4080
+ return true;
4081
+ }
4082
+
4083
+ function agentClear() {
4084
+ agentMarks = [];
4085
+ drop(agentHost);
4086
+ agentHost = agentRoot = agentLayer = agentCursor = null;
4087
+ if (agentListening) {
4088
+ W.removeEventListener('scroll', drawAgentMarks, true);
4089
+ W.removeEventListener('resize', drawAgentMarks);
4090
+ agentListening = false;
4091
+ }
4092
+ }
4093
+
4094
+ function enable(origin, a) {
4095
+ driver = origin;
4096
+ accent = typeof a === 'string' && ACCENT_RE.test(a) ? a : DEFAULT_ACCENT;
4097
+ if (!on) {
4098
+ on = true;
4099
+ build();
4100
+ for (var i = 0; i < HANDLERS.length; i++) {
4101
+ W.addEventListener(HANDLERS[i][0], HANDLERS[i][1], { capture: true, passive: false });
4102
+ bound.push(HANDLERS[i]);
4103
+ }
4104
+ W.addEventListener('scroll', onScroll, true);
4105
+ W.addEventListener('resize', onScroll, true);
4106
+ }
4107
+ send(MULTI ? 'ready' : 'on');
4108
+ }
4109
+
4110
+ function off(pinned) {
4111
+ if (!on) return;
4112
+ on = false;
4113
+ while (bound.length) {
4114
+ var h = bound.pop();
4115
+ W.removeEventListener(h[0], h[1], { capture: true });
4116
+ }
4117
+ W.removeEventListener('scroll', onScroll, true);
4118
+ W.removeEventListener('resize', onScroll, true);
4119
+ D.documentElement.removeAttribute('data-remix-pointing');
4120
+ if (style && style.parentNode) style.parentNode.removeChild(style);
4121
+ var node = host;
4122
+ if (pinned && node && !reduced()) {
4123
+ // A short "pinned" beat before the ring goes, so the tap feels taken.
4124
+ ring.style.transition = 'transform .32s ' + EASE + ', opacity .32s';
4125
+ ring.style.transform += ' scale(1.04)';
4126
+ ring.style.opacity = '0';
4127
+ veil.style.opacity = '0';
4128
+ chip.style.opacity = '0';
4129
+ leaving = node;
4130
+ W.setTimeout(function () {
4131
+ if (node.parentNode) node.parentNode.removeChild(node);
4132
+ if (leaving === node) leaving = null;
4133
+ }, 320);
4134
+ } else if (node && node.parentNode) {
4135
+ node.parentNode.removeChild(node);
4136
+ }
4137
+ host = veil = ring = chip = style = null;
4138
+ current = null;
4139
+ down = null;
4140
+ tapped = false;
4141
+ }
4142
+
4143
+ W.addEventListener('message', function (e) {
4144
+ if (ALLOWED.indexOf(e.origin) === -1 || e.source !== W.parent) return;
4145
+ var d = e.data;
4146
+ if (!d || typeof d !== 'object' || d[FIELD] !== CH) return;
4147
+ if (d.type === 'enable') enable(e.origin, d.accent);
4148
+ else if (d.type === 'disable' && e.origin === driver) off(false);
4149
+ else if (MULTI && d.type === 'marks' && d.ids && d.ids.length !== undefined) syncMarks(d.ids);
4150
+ else if (AGENT && d.type === 'agent-highlight' && d.selector) agentHighlight(d.selector, d.label);
4151
+ else if (AGENT && d.type === 'agent-clear') agentClear();
4152
+ });
4153
+
4154
+ if (!MULTI) {
4155
+ try {
4156
+ Object.defineProperty(W, '__remixPoint', {
4157
+ value: Object.freeze({ version: 1, active: function () { return on; } })
4158
+ });
4159
+ } catch (e) {}
4160
+ }
4161
+
4162
+ // The React Native door. Only where the bridge exists: on a normal page it
4163
+ // would be a global that turns the picker on with nobody's permission.
4164
+ if (GLOBAL && rnBridge()) {
4165
+ W[GLOBAL] = {
4166
+ enable: function () { enable('react-native'); },
4167
+ disable: function () { off(false); },
4168
+ marks: function (ids) { if (MULTI && ids && ids.length !== undefined) syncMarks(ids); },
4169
+ highlight: function (selector, text) { return AGENT ? agentHighlight(selector, text) : false; },
4170
+ clear: function () { if (AGENT) agentClear(); }
4171
+ };
4172
+ }
4173
+ } catch (e) {
4174
+ // Whatever happens, the person's app keeps working.
4175
+ }
4176
+ })();`;
4177
+ }
4178
+
3461
4179
  // src/config.ts
3462
4180
  var fs3 = __toESM(require("fs"));
3463
4181
  var os2 = __toESM(require("os"));
@@ -10636,7 +11354,7 @@ function readAnonId() {
10636
11354
  }
10637
11355
  function superProperties() {
10638
11356
  return {
10639
- cliVersion: true ? "2.76.35" : "0.0.0-dev",
11357
+ cliVersion: true ? "2.76.37" : "0.0.0-dev",
10640
11358
  nodeVersion: process.version,
10641
11359
  platform: process.platform,
10642
11360
  arch: process.arch,
@@ -10885,7 +11603,7 @@ var http = __toESM(require("http"));
10885
11603
  // package.json
10886
11604
  var package_default = {
10887
11605
  name: "codeam-cli",
10888
- version: "2.76.35",
11606
+ version: "2.76.37",
10889
11607
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
10890
11608
  type: "commonjs",
10891
11609
  main: "dist/index.js",
@@ -12261,7 +12979,7 @@ var CommandRelayService = class _CommandRelayService {
12261
12979
  // fresh + clear the "CLI update available" banner after a self-update
12262
12980
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12263
12981
  // pair/reconnect). Older backends ignore the extra field.
12264
- ..."2.76.35" ? { ideVersion: "2.76.35" } : {}
12982
+ ..."2.76.37" ? { ideVersion: "2.76.37" } : {}
12265
12983
  };
12266
12984
  try {
12267
12985
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
@@ -23395,27 +24113,153 @@ var import_os10 = __toESM(require("os"));
23395
24113
  var import_path5 = __toESM(require("path"));
23396
24114
  var import_promises3 = require("stream/promises");
23397
24115
  var import_which = __toESM(require("which"));
23398
- var CACHED_BINARY = import_path5.default.join(import_os10.default.homedir(), ".codeam", "bin", "cloudflared");
24116
+ var CACHE_DIR = import_path5.default.join(import_os10.default.homedir(), ".codeam", "bin");
24117
+ var LEGACY_CACHED_BINARY = import_path5.default.join(CACHE_DIR, "cloudflared");
24118
+ function cachedCloudflaredPath(platform3 = process.platform) {
24119
+ return platform3 === "win32" ? import_path5.default.join(CACHE_DIR, "cloudflared.exe") : LEGACY_CACHED_BINARY;
24120
+ }
24121
+ var MIN_CLOUDFLARED_VERSION = [2026, 10, 2];
24122
+ var MIN_CLOUDFLARED_VERSION_DARWIN_NON_BREW = [2026, 10, 3];
24123
+ var DEFAULT_HOMEBREW_PREFIXES = [
24124
+ "/opt/homebrew/",
24125
+ "/usr/local/Cellar/",
24126
+ "/usr/local/Homebrew/",
24127
+ "/home/linuxbrew/"
24128
+ ];
24129
+ function homebrewPrefixes(env = process.env) {
24130
+ const custom = env.HOMEBREW_PREFIX?.replace(/\/+$/, "");
24131
+ return custom ? [...DEFAULT_HOMEBREW_PREFIXES, `${custom}/`, `${custom}/Cellar/`] : [...DEFAULT_HOMEBREW_PREFIXES];
24132
+ }
24133
+ function parseCloudflaredVersion(output) {
24134
+ const m = /cloudflared version (\d+)\.(\d+)\.(\d+)/.exec(output);
24135
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
24136
+ }
24137
+ function isHomebrewPath(bin, prefixes = homebrewPrefixes()) {
24138
+ return prefixes.some((prefix) => bin.startsWith(prefix));
24139
+ }
24140
+ function formatCloudflaredVersion(v) {
24141
+ return v.join(".");
24142
+ }
24143
+ function minimumCloudflaredVersion(bin, platform3 = process.platform, prefixes = homebrewPrefixes()) {
24144
+ return platform3 === "darwin" && !isHomebrewPath(bin, prefixes) ? MIN_CLOUDFLARED_VERSION_DARWIN_NON_BREW : MIN_CLOUDFLARED_VERSION;
24145
+ }
24146
+ function compareVersions(a, b) {
24147
+ for (let i = 0; i < 3; i++) {
24148
+ if (a[i] !== b[i]) return a[i] - b[i];
24149
+ }
24150
+ return 0;
24151
+ }
24152
+ function meetsMinimumCloudflaredVersion(version3, bin, platform3 = process.platform, prefixes = homebrewPrefixes()) {
24153
+ if (!version3) return false;
24154
+ return compareVersions(version3, minimumCloudflaredVersion(bin, platform3, prefixes)) >= 0;
24155
+ }
24156
+ var versionCache = /* @__PURE__ */ new Map();
24157
+ var warnedOutdated = /* @__PURE__ */ new Set();
24158
+ function readCloudflaredVersion(bin) {
24159
+ let cached2 = versionCache.get(bin);
24160
+ if (!cached2) {
24161
+ const pending2 = new Promise((resolve13) => {
24162
+ (0, import_child_process14.execFile)(bin, ["--version"], { timeout: 1e4 }, (err, stdout, stderr) => {
24163
+ resolve13(err ? null : parseCloudflaredVersion(`${stdout}
24164
+ ${stderr}`));
24165
+ });
24166
+ }).then((version3) => {
24167
+ if (!version3 && versionCache.get(bin) === pending2) versionCache.delete(bin);
24168
+ return version3;
24169
+ });
24170
+ cached2 = pending2;
24171
+ versionCache.set(bin, pending2);
24172
+ }
24173
+ return cached2;
24174
+ }
24175
+ async function realpathOrSelf(p2) {
24176
+ try {
24177
+ return await import_promises2.default.realpath(p2);
24178
+ } catch {
24179
+ return p2;
24180
+ }
24181
+ }
24182
+ async function checkCloudflaredVersion(bin) {
24183
+ const version3 = await readCloudflaredVersion(bin);
24184
+ const real = await realpathOrSelf(bin);
24185
+ const prefixes = homebrewPrefixes();
24186
+ const customPrefix = process.env.HOMEBREW_PREFIX?.replace(/\/+$/, "");
24187
+ if (customPrefix) {
24188
+ const realPrefix = await realpathOrSelf(customPrefix);
24189
+ if (realPrefix !== customPrefix) prefixes.push(`${realPrefix}/`, `${realPrefix}/Cellar/`);
24190
+ }
24191
+ const brewBin = isHomebrewPath(bin, prefixes) ? bin : real;
24192
+ return {
24193
+ ok: meetsMinimumCloudflaredVersion(version3, brewBin, process.platform, prefixes),
24194
+ version: version3,
24195
+ min: minimumCloudflaredVersion(brewBin, process.platform, prefixes)
24196
+ };
24197
+ }
24198
+ async function migrateLegacyWindowsCache(target) {
24199
+ if (target === LEGACY_CACHED_BINARY) return;
24200
+ try {
24201
+ await import_promises2.default.access(target);
24202
+ return;
24203
+ } catch {
24204
+ }
24205
+ try {
24206
+ await import_promises2.default.access(LEGACY_CACHED_BINARY);
24207
+ await import_promises2.default.rename(LEGACY_CACHED_BINARY, target);
24208
+ } catch {
24209
+ }
24210
+ }
24211
+ function describeVersion(v) {
24212
+ return v ? formatCloudflaredVersion(v) : "an unknown version";
24213
+ }
23399
24214
  async function resolveCloudflared(opts = {}) {
24215
+ let pathBin;
23400
24216
  try {
23401
- return await (0, import_which.default)("cloudflared");
24217
+ pathBin = await (0, import_which.default)("cloudflared");
23402
24218
  } catch {
23403
24219
  }
24220
+ if (pathBin) {
24221
+ const check2 = await checkCloudflaredVersion(pathBin);
24222
+ if (check2.ok) return pathBin;
24223
+ if (!warnedOutdated.has(pathBin)) {
24224
+ warnedOutdated.add(pathBin);
24225
+ log.warn(
24226
+ "preview",
24227
+ `ignoring ${pathBin} (${describeVersion(check2.version)}): previews need cloudflared >= ${formatCloudflaredVersion(check2.min)}; upgrade cloudflared with your package manager (e.g. \`brew upgrade cloudflared\`). Using a CodeAgent-managed copy instead.`
24228
+ );
24229
+ }
24230
+ }
24231
+ const cached2 = cachedCloudflaredPath();
24232
+ await migrateLegacyWindowsCache(cached2);
24233
+ let staleCache = false;
23404
24234
  try {
23405
- await import_promises2.default.access(CACHED_BINARY);
23406
- if (await isExecutableBinary(CACHED_BINARY)) {
23407
- return CACHED_BINARY;
24235
+ await import_promises2.default.access(cached2);
24236
+ if (!await isExecutableBinary(cached2)) {
24237
+ await import_promises2.default.rm(cached2, { force: true });
24238
+ } else if ((await checkCloudflaredVersion(cached2)).ok) {
24239
+ return cached2;
24240
+ } else {
24241
+ staleCache = true;
23408
24242
  }
23409
- await import_promises2.default.rm(CACHED_BINARY, { force: true });
23410
24243
  } catch {
23411
24244
  }
23412
24245
  if (opts.skipDownload) {
23413
24246
  throw new Error(
23414
- "cloudflared not installed. Install via `brew install cloudflared` (macOS) or download from https://github.com/cloudflare/cloudflared/releases."
24247
+ `cloudflared not installed (or older than ${formatCloudflaredVersion(minimumCloudflaredVersion(cached2))}). Install or upgrade via \`brew install cloudflared\` (macOS) or download from https://github.com/cloudflare/cloudflared/releases.`
23415
24248
  );
23416
24249
  }
23417
- await downloadCloudflared(CACHED_BINARY);
23418
- return CACHED_BINARY;
24250
+ if (staleCache) await import_promises2.default.rm(cached2, { force: true });
24251
+ versionCache.delete(cached2);
24252
+ await downloadCloudflared(cached2);
24253
+ versionCache.delete(cached2);
24254
+ const check = await checkCloudflaredVersion(cached2);
24255
+ if (!check.ok) {
24256
+ await import_promises2.default.rm(cached2, { force: true });
24257
+ versionCache.delete(cached2);
24258
+ throw new Error(
24259
+ `Downloaded cloudflared reports ${describeVersion(check.version)}, but previews need cloudflared >= ${formatCloudflaredVersion(check.min)}. Install the latest version manually via \`brew install cloudflared\` (macOS) or from https://github.com/cloudflare/cloudflared/releases.`
24260
+ );
24261
+ }
24262
+ return cached2;
23419
24263
  }
23420
24264
  async function downloadCloudflared(target) {
23421
24265
  const url2 = downloadUrlForPlatform();
@@ -26453,470 +27297,22 @@ async function startInspectorProxy(opts) {
26453
27297
 
26454
27298
  // src/services/preview/inspector-client.ts
26455
27299
  var INSPECTOR_CHANNEL = "codeam-inspector";
27300
+ var INSPECTOR_MAX_MARKS = 4;
27301
+ var INSPECTOR_ACCENT = "#a855f7";
26456
27302
  function inspectorClientSource(opts) {
26457
- const origins = JSON.stringify(opts.allowedOrigins);
26458
- const channel = JSON.stringify(INSPECTOR_CHANNEL);
27303
+ const script = pointPickerScript({
27304
+ channel: INSPECTOR_CHANNEL,
27305
+ channelField: "source",
27306
+ allowedParents: opts.allowedOrigins,
27307
+ mode: "multi",
27308
+ maxMarks: INSPECTOR_MAX_MARKS,
27309
+ accent: INSPECTOR_ACCENT,
27310
+ agentHighlights: true,
27311
+ reactSource: true,
27312
+ globalName: "__codeamInspector"
27313
+ });
26459
27314
  return `<script id="codeam-inspector" data-codeam="inspector">
26460
- (function () {
26461
- 'use strict';
26462
- try {
26463
- var CHANNEL = ${channel};
26464
- var ALLOWED = ${origins};
26465
-
26466
- var enabled = false;
26467
- var driver = null; // el origen que nos encendio
26468
- var overlay = null;
26469
- var label = null;
26470
- var current = null;
26471
-
26472
- function allowed(origin) {
26473
- return ALLOWED.indexOf(origin) !== -1;
26474
- }
26475
-
26476
- // \xBFEstamos dentro del WebView de la app movil?
26477
- //
26478
- // \u26A0\uFE0F En un WebView el documento es de NIVEL SUPERIOR, asi que
26479
- // \`window.parent === window\` y la via del iframe no existe: el script
26480
- // hablaba solo, y en movil el inspector no devolvia nada. React Native
26481
- // expone su propio canal, que es el unico que sale de ahi.
26482
- function rnBridge() {
26483
- return typeof window.ReactNativeWebView !== 'undefined' &&
26484
- window.ReactNativeWebView &&
26485
- typeof window.ReactNativeWebView.postMessage === 'function'
26486
- ? window.ReactNativeWebView
26487
- : null;
26488
- }
26489
-
26490
- function send(type, payload) {
26491
- if (!driver) return;
26492
- var msg = { source: CHANNEL, type: type };
26493
- for (var k in payload) if (Object.prototype.hasOwnProperty.call(payload, k)) msg[k] = payload[k];
26494
-
26495
- var rn = rnBridge();
26496
- if (rn) {
26497
- // El canal de RN transporta CADENAS, no objetos: pasarle el objeto
26498
- // llega al otro lado como "[object Object]".
26499
- rn.postMessage(JSON.stringify(msg));
26500
- return;
26501
- }
26502
- if (window.parent === window) return;
26503
- window.parent.postMessage(msg, driver);
26504
- }
26505
-
26506
- // El resaltado. Un div fijo por encima de todo que NUNCA captura el
26507
- // puntero: si lo capturara, el elemento de debajo dejaria de recibir el
26508
- // mousemove y el resaltado se quedaria pegado al primero que tocara.
26509
- function ensureOverlay() {
26510
- if (overlay) return;
26511
- overlay = document.createElement('div');
26512
- overlay.setAttribute('data-codeam', 'inspector-overlay');
26513
- overlay.style.cssText = [
26514
- 'position:fixed', 'pointer-events:none', 'z-index:2147483647',
26515
- 'border:1px solid #a855f7', 'background:rgba(168,85,247,0.14)',
26516
- 'border-radius:2px', 'transition:none', 'display:none'
26517
- ].join(';');
26518
- label = document.createElement('div');
26519
- label.setAttribute('data-codeam', 'inspector-label');
26520
- label.style.cssText = [
26521
- 'position:fixed', 'pointer-events:none', 'z-index:2147483647',
26522
- 'background:#a855f7', 'color:#000', 'font:600 11px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace',
26523
- 'padding:2px 6px', 'border-radius:3px', 'white-space:nowrap', 'display:none'
26524
- ].join(';');
26525
- document.body.appendChild(overlay);
26526
- document.body.appendChild(label);
26527
- }
26528
-
26529
- function removeOverlay() {
26530
- if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);
26531
- if (label && label.parentNode) label.parentNode.removeChild(label);
26532
- overlay = null;
26533
- label = null;
26534
- }
26535
-
26536
- // Fichero y linea del componente de React, cuando el dev server los
26537
- // expone. Es lo que hace que el agente reciba
26538
- // "components/whatsapp-button.tsx:42" en vez de "x:0.62 y:0.81".
26539
- // Solo existe en builds de desarrollo; en produccion devuelve null y se
26540
- // cae al selector CSS.
26541
- function reactSource(el) {
26542
- try {
26543
- for (var key in el) {
26544
- if (key.indexOf('__reactFiber$') !== 0) continue;
26545
- var fiber = el[key];
26546
- while (fiber) {
26547
- var src = fiber._debugSource;
26548
- if (src && src.fileName) {
26549
- return { file: String(src.fileName), line: Number(src.lineNumber) || null };
26550
- }
26551
- fiber = fiber.return;
26552
- }
26553
- }
26554
- } catch (e) { /* nunca romper la pagina por esto */ }
26555
- return null;
26556
- }
26557
-
26558
- // Un selector corto y legible, el respaldo cuando no hay React.
26559
- function selectorFor(el) {
26560
- if (el.id) return '#' + el.id;
26561
- var name = el.tagName ? el.tagName.toLowerCase() : 'node';
26562
- var cls = (el.className && typeof el.className === 'string')
26563
- ? el.className.trim().split(/\\s+/).slice(0, 3).join('.')
26564
- : '';
26565
- return cls ? name + '.' + cls : name;
26566
- }
26567
-
26568
- function describe(el) {
26569
- var r = el.getBoundingClientRect();
26570
- var text = (el.textContent || '').replace(/\\s+/g, ' ').trim();
26571
- return {
26572
- tag: el.tagName ? el.tagName.toLowerCase() : 'node',
26573
- id: el.id || null,
26574
- classes: (el.className && typeof el.className === 'string') ? el.className.trim() : '',
26575
- selector: selectorFor(el),
26576
- // Un recorte, no el contenido: describir no es extraer.
26577
- text: text.length > 120 ? text.slice(0, 120) + '\u2026' : text,
26578
- rect: { x: r.left, y: r.top, w: r.width, h: r.height },
26579
- viewport: { w: window.innerWidth, h: window.innerHeight },
26580
- source: reactSource(el)
26581
- };
26582
- }
26583
-
26584
- function paint(el) {
26585
- ensureOverlay();
26586
- var r = el.getBoundingClientRect();
26587
- overlay.style.display = 'block';
26588
- overlay.style.left = r.left + 'px';
26589
- overlay.style.top = r.top + 'px';
26590
- overlay.style.width = r.width + 'px';
26591
- overlay.style.height = r.height + 'px';
26592
- label.style.display = 'block';
26593
- label.textContent = selectorFor(el) + ' ' + Math.round(r.width) + '\xD7' + Math.round(r.height);
26594
- // Encima si cabe; si no, dentro. Una etiqueta cortada por el borde
26595
- // superior no se lee.
26596
- var above = r.top >= 20;
26597
- label.style.left = r.left + 'px';
26598
- label.style.top = (above ? r.top - 20 : r.top + 2) + 'px';
26599
- }
26600
-
26601
- function onMove(e) {
26602
- if (!enabled) return;
26603
- var el = e.target;
26604
- if (!el || el === current || !el.getBoundingClientRect) return;
26605
- if (el.getAttribute && el.getAttribute('data-codeam')) return;
26606
- current = el;
26607
- paint(el);
26608
- send('hover', { element: describe(el) });
26609
- }
26610
-
26611
- // Captura, y se traga el evento: mientras el modo esta activo un clic
26612
- // SELECCIONA, no navega. Sin esto, pulsar un enlace se llevaria el
26613
- // preview a otra pagina en mitad del gesto.
26614
- /**
26615
- * Las marcas FIJADAS, dibujadas DENTRO de la pagina.
26616
- *
26617
- * \u26A0\uFE0F Antes las pintaba el dashboard, en una capa sobre el iframe. Como esa
26618
- * capa vive fuera del documento, sus coordenadas son del VIEWPORT: al
26619
- * hacer scroll dentro del preview las marcas se quedaban clavadas en la
26620
- * pantalla mientras el elemento se iba (reportado el 2026-08-29).
26621
- *
26622
- * Aqui se anclan al DOCUMENTO (position:absolute mas el scroll sumado), asi
26623
- * que acompa\xF1an al contenido igual que cualquier otro nodo de la pagina \u2014 y
26624
- * ademas se recolocan si el layout cambia, que una capa externa no puede
26625
- * saber.
26626
- */
26627
- var picked = [];
26628
- var seq = 0;
26629
- var marksHost = null;
26630
-
26631
- function ensureMarksHost() {
26632
- if (marksHost && marksHost.parentNode) return marksHost;
26633
- marksHost = document.createElement('div');
26634
- marksHost.setAttribute('data-codeam', 'marks');
26635
- marksHost.style.cssText = 'position:absolute;left:0;top:0;width:0;height:0;z-index:2147483646';
26636
- document.body.appendChild(marksHost);
26637
- return marksHost;
26638
- }
26639
-
26640
- function redrawMarks() {
26641
- if (picked.length === 0) {
26642
- if (marksHost && marksHost.parentNode) marksHost.parentNode.removeChild(marksHost);
26643
- marksHost = null;
26644
- return;
26645
- }
26646
- var host = ensureMarksHost();
26647
- host.innerHTML = '';
26648
- for (var i = 0; i < picked.length; i++) {
26649
- var r = picked[i].el.getBoundingClientRect();
26650
- // Coordenadas de DOCUMENTO: es lo que hace que la marca viaje con el
26651
- // contenido en vez de quedarse pegada a la pantalla.
26652
- var top = r.top + (window.scrollY || window.pageYOffset || 0);
26653
- var left = r.left + (window.scrollX || window.pageXOffset || 0);
26654
-
26655
- var box = document.createElement('div');
26656
- box.setAttribute('data-codeam', 'mark');
26657
- box.style.cssText = [
26658
- 'position:absolute', 'pointer-events:none', 'box-sizing:border-box',
26659
- 'border:1.5px solid #a855f7', 'background:rgba(168,85,247,0.12)',
26660
- 'border-radius:3px',
26661
- 'left:' + left + 'px', 'top:' + top + 'px',
26662
- 'width:' + r.width + 'px', 'height:' + r.height + 'px'
26663
- ].join(';');
26664
-
26665
- var badge = document.createElement('div');
26666
- badge.setAttribute('data-codeam', 'mark-badge');
26667
- badge.style.cssText = [
26668
- 'position:absolute', 'left:-10px', 'top:-10px', 'width:20px', 'height:20px',
26669
- 'border-radius:10px', 'background:#a855f7', 'color:#000',
26670
- 'font:700 11px/20px ui-monospace,SFMono-Regular,Menlo,monospace',
26671
- 'text-align:center', 'pointer-events:none'
26672
- ].join(';');
26673
- badge.textContent = String(i + 1);
26674
-
26675
- box.appendChild(badge);
26676
- host.appendChild(box);
26677
- }
26678
- }
26679
-
26680
- function reposition() { if (picked.length) redrawMarks(); }
26681
-
26682
- // Captura, y se traga el evento: mientras el modo esta activo un clic
26683
- // SELECCIONA, no navega. Sin esto, pulsar un enlace se llevaria el
26684
- // preview a otra pagina en mitad del gesto.
26685
- function onClick(e) {
26686
- if (!enabled) return;
26687
- var el = e.target;
26688
- if (el && el.getAttribute && el.getAttribute('data-codeam')) return;
26689
- e.preventDefault();
26690
- e.stopPropagation();
26691
- if (!el) return;
26692
- var id = 'p' + (++seq);
26693
- picked.push({ id: id, el: el });
26694
- redrawMarks();
26695
- var described = describe(el);
26696
- described.markId = id;
26697
- send('pick', { element: described });
26698
- }
26699
-
26700
- /**
26701
- * El dashboard manda la lista de ids que SIGUEN vivos, en su orden.
26702
- *
26703
- * Es la otra mitad de \xABla marca es un objeto\xBB: si el usuario borra un chip
26704
- * en el composer, la marca tiene que desaparecer de la pagina \u2014 y las que
26705
- * quedan renumerarse, porque lo que el usuario escribe (\xAB\u2460 se sale\xBB) mira
26706
- * a estos numeros.
26707
- */
26708
- function syncMarks(ids) {
26709
- var byId = {};
26710
- for (var i = 0; i < picked.length; i++) byId[picked[i].id] = picked[i];
26711
- var next = [];
26712
- for (var j = 0; j < ids.length; j++) if (byId[ids[j]]) next.push(byId[ids[j]]);
26713
- picked = next;
26714
- redrawMarks();
26715
- }
26716
-
26717
- /**
26718
- * Las marcas del AGENTE \u2014 la herramienta highlight_element.
26719
- *
26720
- * Van aparte de las del usuario a proposito: no se numeran, no se pueden
26721
- * borrar desde el composer y no dependen de que el modo inspector este
26722
- * encendido. Son el agente SE\xD1ALANDO algo, y el usuario las ve aunque no
26723
- * haya tocado nada: un cursor que viaja hasta el elemento, lo centra en
26724
- * pantalla y deja una caja con su etiqueta.
26725
- *
26726
- * Mismo anclaje que las marcas fijadas (coordenadas de documento), asi que
26727
- * acompa\xF1an al scroll. Un selector que no encuentra nada no pinta nada: el
26728
- * agente ya sabe por la herramienta que puede fallar.
26729
- */
26730
- var AGENT = '#22d3ee';
26731
- var agentMarks = [];
26732
- var agentHost = null;
26733
- var agentCursor = null;
26734
- var agentStyle = null;
26735
- var agentListening = false;
26736
-
26737
- function ensureAgentStyle() {
26738
- if (agentStyle && agentStyle.parentNode) return;
26739
- agentStyle = document.createElement('style');
26740
- agentStyle.setAttribute('data-codeam', 'agent-style');
26741
- agentStyle.textContent =
26742
- '@keyframes codeam-agent-pulse{0%{box-shadow:0 0 0 0 rgba(34,211,238,.55)}' +
26743
- '70%{box-shadow:0 0 0 10px rgba(34,211,238,0)}100%{box-shadow:0 0 0 0 rgba(34,211,238,0)}}' +
26744
- '@keyframes codeam-agent-in{from{opacity:0;transform:scale(1.06)}to{opacity:1;transform:scale(1)}}';
26745
- (document.head || document.documentElement).appendChild(agentStyle);
26746
- }
26747
-
26748
- function ensureAgentCursor() {
26749
- if (agentCursor && agentCursor.parentNode) return agentCursor;
26750
- agentCursor = document.createElement('div');
26751
- agentCursor.setAttribute('data-codeam', 'agent-cursor');
26752
- agentCursor.style.cssText = [
26753
- 'position:fixed', 'pointer-events:none', 'z-index:2147483647',
26754
- 'left:' + Math.round(window.innerWidth / 2) + 'px', 'top:' + Math.round(window.innerHeight - 40) + 'px',
26755
- 'transition:left .6s cubic-bezier(.22,1,.36,1),top .6s cubic-bezier(.22,1,.36,1),opacity .3s',
26756
- 'opacity:0'
26757
- ].join(';');
26758
- agentCursor.innerHTML =
26759
- '<svg width="22" height="22" viewBox="0 0 24 24" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))">' +
26760
- '<path d="M4 2l15 8.5-6.6 1.6L9 18.5z" fill="' + AGENT + '" stroke="#000" stroke-width="1.2"/></svg>' +
26761
- '<div style="margin:2px 0 0 14px;background:' + AGENT + ';color:#000;font:700 10px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;' +
26762
- 'padding:1px 6px;border-radius:8px;white-space:nowrap">Agent</div>';
26763
- document.body.appendChild(agentCursor);
26764
- return agentCursor;
26765
- }
26766
-
26767
- function redrawAgentMarks() {
26768
- if (agentMarks.length === 0) {
26769
- if (agentHost && agentHost.parentNode) agentHost.parentNode.removeChild(agentHost);
26770
- agentHost = null;
26771
- return;
26772
- }
26773
- if (!agentHost || !agentHost.parentNode) {
26774
- agentHost = document.createElement('div');
26775
- agentHost.setAttribute('data-codeam', 'agent-marks');
26776
- agentHost.style.cssText = 'position:absolute;left:0;top:0;width:0;height:0;z-index:2147483646';
26777
- document.body.appendChild(agentHost);
26778
- }
26779
- agentHost.innerHTML = '';
26780
- var sx = window.scrollX || window.pageXOffset || 0;
26781
- var sy = window.scrollY || window.pageYOffset || 0;
26782
- for (var i = 0; i < agentMarks.length; i++) {
26783
- var m = agentMarks[i];
26784
- if (!m.el.isConnected) continue;
26785
- var r = m.el.getBoundingClientRect();
26786
- var box = document.createElement('div');
26787
- box.setAttribute('data-codeam', 'agent-mark');
26788
- box.style.cssText = [
26789
- 'position:absolute', 'pointer-events:none', 'box-sizing:border-box',
26790
- 'border:2px solid ' + AGENT, 'background:rgba(34,211,238,0.10)', 'border-radius:4px',
26791
- 'left:' + (r.left + sx - 3) + 'px', 'top:' + (r.top + sy - 3) + 'px',
26792
- 'width:' + (r.width + 6) + 'px', 'height:' + (r.height + 6) + 'px',
26793
- 'animation:codeam-agent-in .25s ease-out,codeam-agent-pulse 1.6s ease-out 3'
26794
- ].join(';');
26795
- if (m.label) {
26796
- var tag = document.createElement('div');
26797
- tag.setAttribute('data-codeam', 'agent-mark-label');
26798
- tag.style.cssText = [
26799
- 'position:absolute', 'left:-2px', (r.top >= 22 ? 'top:-22px' : 'bottom:-22px'),
26800
- 'background:' + AGENT, 'color:#000', 'font:700 11px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace',
26801
- 'padding:0 6px', 'border-radius:3px', 'white-space:nowrap', 'max-width:260px',
26802
- 'overflow:hidden', 'text-overflow:ellipsis'
26803
- ].join(';');
26804
- tag.textContent = m.label;
26805
- box.appendChild(tag);
26806
- }
26807
- agentHost.appendChild(box);
26808
- }
26809
- }
26810
-
26811
- function listenAgentLayout() {
26812
- if (agentListening) return;
26813
- agentListening = true;
26814
- window.addEventListener('scroll', redrawAgentMarks, true);
26815
- window.addEventListener('resize', redrawAgentMarks);
26816
- }
26817
-
26818
- function agentHighlight(selector, labelText) {
26819
- var el = null;
26820
- try { el = document.querySelector(String(selector)); } catch (e) { el = null; }
26821
- if (!el || !el.getBoundingClientRect) return false;
26822
- ensureAgentStyle();
26823
- listenAgentLayout();
26824
- try { el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' }); } catch (e) { /* viejo */ }
26825
- var cursor = ensureAgentCursor();
26826
- // Tras el scroll suave: el cursor viaja al centro del elemento y, al
26827
- // llegar, aparece la caja. El orden es lo que se lee como \xABel agente
26828
- // lo esta se\xF1alando\xBB y no como un recuadro que salta.
26829
- setTimeout(function () {
26830
- var r = el.getBoundingClientRect();
26831
- cursor.style.opacity = '1';
26832
- cursor.style.left = Math.round(r.left + Math.min(r.width / 2, 40)) + 'px';
26833
- cursor.style.top = Math.round(r.top + Math.min(r.height / 2, 24)) + 'px';
26834
- setTimeout(function () {
26835
- agentMarks.push({ el: el, label: labelText ? String(labelText).slice(0, 80) : '' });
26836
- redrawAgentMarks();
26837
- }, 620);
26838
- }, 380);
26839
- return true;
26840
- }
26841
-
26842
- function agentClear() {
26843
- agentMarks = [];
26844
- redrawAgentMarks();
26845
- if (agentCursor && agentCursor.parentNode) agentCursor.parentNode.removeChild(agentCursor);
26846
- agentCursor = null;
26847
- if (agentStyle && agentStyle.parentNode) agentStyle.parentNode.removeChild(agentStyle);
26848
- agentStyle = null;
26849
- if (agentListening) {
26850
- window.removeEventListener('scroll', redrawAgentMarks, true);
26851
- window.removeEventListener('resize', redrawAgentMarks);
26852
- agentListening = false;
26853
- }
26854
- }
26855
-
26856
- function enable(origin) {
26857
- if (enabled) return;
26858
- enabled = true;
26859
- driver = origin;
26860
- document.addEventListener('mousemove', onMove, true);
26861
- document.addEventListener('click', onClick, true);
26862
- // El scroll y el resize mueven los elementos; las marcas los siguen.
26863
- window.addEventListener('scroll', reposition, true);
26864
- window.addEventListener('resize', reposition);
26865
- send('ready', {});
26866
- }
26867
-
26868
- function disable() {
26869
- if (!enabled) return;
26870
- enabled = false;
26871
- current = null;
26872
- document.removeEventListener('mousemove', onMove, true);
26873
- document.removeEventListener('click', onClick, true);
26874
- window.removeEventListener('scroll', reposition, true);
26875
- window.removeEventListener('resize', reposition);
26876
- removeOverlay();
26877
- // Las marcas fijadas SI sobreviven a salir del modo: siguen siendo el
26878
- // contexto del mensaje que el usuario esta escribiendo.
26879
- driver = null;
26880
- }
26881
-
26882
- window.addEventListener('message', function (e) {
26883
- if (!allowed(e.origin)) return;
26884
- var data = e.data;
26885
- if (!data || data.source !== CHANNEL) return;
26886
- if (data.type === 'enable') enable(e.origin);
26887
- else if (data.type === 'disable') disable();
26888
- else if (data.type === 'marks' && data.ids) syncMarks(data.ids);
26889
- else if (data.type === 'agent-highlight' && data.selector) agentHighlight(data.selector, data.label);
26890
- else if (data.type === 'agent-clear') agentClear();
26891
- });
26892
-
26893
- /**
26894
- * La puerta para React Native, que no puede usar \`postMessage\`.
26895
- *
26896
- * \u26A0\uFE0F Aqui NO hay lista blanca de origenes, y no es un descuido: quien
26897
- * llama esto es la app anfitriona sobre SU PROPIO WebView, via
26898
- * \`injectJavaScript\` \u2014 no hay un tercero al que filtrar. La lista blanca
26899
- * protege el caso del iframe, donde cualquier pagina puede embeber el
26900
- * preview y mandar mensajes; ese caso sigue exactamente igual de cerrado.
26901
- *
26902
- * Solo se expone donde ese puente existe, para no dejar en una pagina
26903
- * normal una funcion global que encienda el inspector sin permiso.
26904
- */
26905
- if (rnBridge()) {
26906
- window.__codeamInspector = {
26907
- enable: function () { enable('react-native'); },
26908
- disable: disable,
26909
- // La app movil ya llamaba \`marks\` al borrar un chip y no existia:
26910
- // la marca se quedaba pintada en la pagina.
26911
- marks: function (ids) { if (ids && ids.length !== undefined) syncMarks(ids); },
26912
- highlight: function (selector, text) { return agentHighlight(selector, text); },
26913
- clear: agentClear,
26914
- };
26915
- }
26916
- } catch (e) {
26917
- // Pase lo que pase, la app del usuario sigue funcionando.
26918
- }
26919
- })();
27315
+ ${script}
26920
27316
  </script>`;
26921
27317
  }
26922
27318
 
@@ -50767,9 +51163,9 @@ async function probeCodeamPair(provider, workspace) {
50767
51163
  }
50768
51164
  async function stopWorkspaceFromLocal(target) {
50769
51165
  if (target.provider.id === "github-codespaces") {
50770
- const { execFile: execFile21 } = await import("child_process");
51166
+ const { execFile: execFile22 } = await import("child_process");
50771
51167
  const { promisify: promisify17 } = await import("util");
50772
- const execFileP10 = promisify17(execFile21);
51168
+ const execFileP10 = promisify17(execFile22);
50773
51169
  await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
50774
51170
  return;
50775
51171
  }
@@ -51667,7 +52063,7 @@ async function autoUpgradeBeforeCriticalCommand() {
51667
52063
  if (process.env.NODE_ENV === "test") return;
51668
52064
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51669
52065
  if (process.env.CI) return;
51670
- const current2 = true ? "2.76.35" : null;
52066
+ const current2 = true ? "2.76.37" : null;
51671
52067
  if (!current2) return;
51672
52068
  const cache = readCache();
51673
52069
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51684,7 +52080,7 @@ function checkForUpdates() {
51684
52080
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51685
52081
  if (process.env.CI) return;
51686
52082
  if (!process.stdout.isTTY) return;
51687
- const current2 = true ? "2.76.35" : null;
52083
+ const current2 = true ? "2.76.37" : null;
51688
52084
  if (!current2) return;
51689
52085
  const cache = readCache();
51690
52086
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51990,7 +52386,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
51990
52386
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
51991
52387
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
51992
52388
  function currentCliVersion() {
51993
- return true ? "2.76.35" : null;
52389
+ return true ? "2.76.37" : null;
51994
52390
  }
51995
52391
  async function installedVersion(deps) {
51996
52392
  const ls = await deps.run(
@@ -52213,7 +52609,7 @@ function signalHostReady(send = process.send?.bind(process)) {
52213
52609
  }
52214
52610
  function defaultDeps() {
52215
52611
  return {
52216
- ownVersion: true ? "2.76.35" : null,
52612
+ ownVersion: true ? "2.76.37" : null,
52217
52613
  root: cliVersionsRoot(),
52218
52614
  args: process.argv.slice(3),
52219
52615
  execPath: process.execPath,
@@ -54751,7 +55147,7 @@ function checkChokidar() {
54751
55147
  }
54752
55148
  async function doctor(args2 = []) {
54753
55149
  const json = args2.includes("--json");
54754
- const cliVersion = true ? "2.76.35" : "0.0.0-dev";
55150
+ const cliVersion = true ? "2.76.37" : "0.0.0-dev";
54755
55151
  const apiBase2 = resolveApiBaseUrl();
54756
55152
  const diagnosticId = (0, import_node_crypto17.randomUUID)();
54757
55153
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -55287,7 +55683,7 @@ async function mcpWarm(argv = [], opts = {}) {
55287
55683
  // src/commands/version.ts
55288
55684
  var import_picocolors15 = __toESM(require("picocolors"));
55289
55685
  function version2() {
55290
- const v = true ? "2.76.35" : "unknown";
55686
+ const v = true ? "2.76.37" : "unknown";
55291
55687
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
55292
55688
  }
55293
55689