cobro-mcp 0.9.0 → 0.9.1

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
@@ -4,6 +4,10 @@ All notable changes to this project are documented here. The format follows [Kee
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.1] — 2026-09-21
8
+ ### Added
9
+ - Working indicator: while the agent is editing (from Send until done), the elements and regions you sent get a blue scanning outline and the toolbar shows a flowing line; respects prefers-reduced-motion.
10
+
7
11
  ## [0.9.0] — 2026-09-21
8
12
  ### Added
9
13
  - Drag groups: dragging over two or more elements picks them as one group — the band becomes a region (ref "1") and the elements inside get "1a", "1b"…; the row is collapsed by default and expands to show or remove them. A band over one element picks just that element. Every element and region now carries a stable `ref` that does not change when other rows are removed.
package/dist/overlay.js CHANGED
@@ -81,6 +81,17 @@
81
81
  .status-in.enter{animation:cobroin .15s ease-out}
82
82
  @keyframes cobroin{from{opacity:.4;transform:translateX(-6px)}to{opacity:1;transform:translateX(0)}}
83
83
  @media (prefers-reduced-motion: reduce){.status-in{transition:none}.status-in.enter{animation:none}}
84
+ .wbox{position:fixed;border:1.5px solid var(--info);border-radius:2px;pointer-events:none;box-sizing:border-box;animation:cobrobreathe 2.4s ease-in-out infinite}
85
+ .wbox.region{border-style:dashed;background:color-mix(in srgb, var(--info) 6%, transparent)}
86
+ .wbox .clip{position:absolute;inset:0;overflow:hidden;border-radius:inherit}
87
+ .wbox .sweep{position:absolute;top:0;bottom:0;left:0;width:55%;background:linear-gradient(90deg,transparent,color-mix(in srgb, var(--info) 55%, transparent),transparent);animation:cobrosweep 2.2s cubic-bezier(.4,0,.2,1) infinite}
88
+ /* \uBC30\uC9C0 \uBC30\uACBD \uD1A0\uD070\uC744 \uAE00\uC790\uC0C9\uC73C\uB85C \u2014 --info \uC704 \uB300\uBE44\uAC00 \uC138 \uD14C\uB9C8 \uBAA8\uB450 \uB9DE\uB294\uB2E4 */
89
+ .wbox .n{position:absolute;left:-2px;top:-2px;transform:translate(-50%,-50%);min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--info);color:var(--badge-bg);font:700 11px/18px ui-monospace,Menlo,Consolas,monospace;text-align:center;box-shadow:0 1px 3px rgba(0,0,0,.4)}
90
+ @keyframes cobrosweep{0%{transform:translateX(-110%)}100%{transform:translateX(300%)}}
91
+ @keyframes cobrobreathe{0%{box-shadow:0 0 0 1px color-mix(in srgb, var(--info) 12%, transparent),0 0 6px color-mix(in srgb, var(--info) 18%, transparent)}50%{box-shadow:0 0 0 3px color-mix(in srgb, var(--info) 16%, transparent),0 0 16px color-mix(in srgb, var(--info) 42%, transparent)}100%{box-shadow:0 0 0 1px color-mix(in srgb, var(--info) 12%, transparent),0 0 6px color-mix(in srgb, var(--info) 18%, transparent)}}
92
+ .toolbar .line{position:absolute;left:20px;right:20px;bottom:0;height:2px;background:linear-gradient(90deg,transparent,var(--info) 30%,var(--accent) 50%,var(--info) 70%,transparent);background-size:200% 100%;background-position:100%;opacity:.9;animation:cobroflow 2.2s linear infinite;pointer-events:none}
93
+ @keyframes cobroflow{from{background-position:100%}to{background-position:-100%}}
94
+ @media (prefers-reduced-motion: reduce){.wbox{animation:none}.wbox .sweep{display:none}.toolbar .line{animation:none}}
84
95
  .panel{position:fixed;right:14px;bottom:60px;width:320px;background:var(--bg-2);border:1px solid var(--accent);border-radius:var(--radius);padding:16px 16px 14px;box-shadow:var(--shadow);pointer-events:auto;display:none}
85
96
  .panel.show{display:block}
86
97
  .panel h4{margin:0 0 12px;color:var(--fg);font-size:12px;font-weight:700;display:flex;align-items:center;gap:6px;cursor:grab;user-select:none}
@@ -113,15 +124,15 @@ textarea{width:100%;min-height:80px;resize:none;font:inherit;color:var(--fg);bac
113
124
  .marker{position:fixed;border:2px solid var(--accent);border-radius:2px;pointer-events:none;box-sizing:border-box}
114
125
  .marker.region{border-style:dashed;background:color-mix(in srgb, var(--accent) 6%, transparent)}
115
126
  .marker .n{position:absolute;left:-2px;top:-2px;transform:translate(-50%,-50%);min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--accent);color:#fff;font:700 11px/18px ui-monospace,Menlo,Consolas,monospace;text-align:center;box-shadow:0 1px 3px rgba(0,0,0,.4)}
116
- .marker.inside-x .n{transform:translate(4px,-50%)}
117
- .marker.inside-y .n{transform:translate(-50%,4px)}
118
- .marker.inside-x.inside-y .n{transform:translate(4px,4px)}
127
+ .marker.inside-x .n,.wbox.inside-x .n{transform:translate(4px,-50%)}
128
+ .marker.inside-y .n,.wbox.inside-y .n{transform:translate(-50%,4px)}
129
+ .marker.inside-x.inside-y .n,.wbox.inside-x.inside-y .n{transform:translate(4px,4px)}
119
130
  .marker.child .n{left:auto;right:-2px;transform:translate(50%,-50%)}
120
131
  .flash{position:fixed;border:2px solid var(--ok);border-radius:2px;pointer-events:none;animation:cobroflash 1.6s ease-out forwards}
121
132
  @keyframes cobroflash{0%{opacity:1}100%{opacity:0}}
122
133
  /* shadow root\uC758 \uC790\uC2DD\uC740 \uBAA8\uB450 position:fixed \uD615\uC81C \u2014 picker\uAC00 glass\uB97C toolbar/panel \uB4A4\uC5D0 append\uD558\uBBC0\uB85C \uC313\uC784 \uC21C\uC11C\uB97C \uBA85\uC2DC\uD55C\uB2E4 */
123
134
  .glass{z-index:0}
124
- .hover-box,.hover-badge,.band,.flash,.marker{z-index:1}
135
+ .hover-box,.hover-badge,.band,.flash,.marker,.wbox{z-index:1}
125
136
  .toolbar,.pop,.panel{z-index:2}
126
137
  .pop{position:fixed;bottom:56px;left:50%;transform:translateX(-50%);display:none;min-width:260px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);padding:10px 12px;box-shadow:var(--shadow);backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);pointer-events:auto;color:var(--fg-2)}
127
138
  .pop.show{display:block}
@@ -352,6 +363,10 @@ textarea{width:100%;min-height:80px;resize:none;font:inherit;color:var(--fg);bac
352
363
  const grip = gripParts.btn;
353
364
  grip.setAttribute("aria-label", "Move toolbar");
354
365
  toolbar.append(grip, selectBtn, chip, chip2, status, gearBtn);
366
+ const line = document.createElement("span");
367
+ line.className = "line";
368
+ line.hidden = true;
369
+ toolbar.append(line);
355
370
  makeDraggable(toolbar, grip);
356
371
  const pop = document.createElement("div");
357
372
  pop.className = "pop";
@@ -640,8 +655,7 @@ textarea{width:100%;min-height:80px;resize:none;font:inherit;color:var(--fg);bac
640
655
  cancelAnimationFrame(markerFrame);
641
656
  markerFrame = requestAnimationFrame(() => {
642
657
  root.querySelectorAll(".marker").forEach((m) => m.remove());
643
- const cur = vm.drafts.length ? vm.drafts[vm.drafts.length - 1] : null;
644
- if (!cur) return;
658
+ root.querySelectorAll(".wbox").forEach((m) => m.remove());
645
659
  const place = (m, left, top, width, height, n) => {
646
660
  Object.assign(m.style, { left: left + "px", top: top + "px", width: width + "px", height: height + "px" });
647
661
  if (left < 12) m.classList.add("inside-x");
@@ -649,23 +663,54 @@ textarea{width:100%;min-height:80px;resize:none;font:inherit;color:var(--fg);bac
649
663
  m.append(el("span", "n", String(n)));
650
664
  root.append(m);
651
665
  };
652
- cur.elements.forEach((e) => {
653
- if (e.missing) return;
654
- const isChild = /[a-z]$/.test(e.ref ?? "");
655
- const groupRef = isChild ? e.ref.slice(0, -1) : null;
656
- if (isChild && vm.expanded !== groupRef) return;
657
- let target = null;
658
- try {
659
- target = document.querySelector(e.selector);
660
- } catch {
666
+ const cur = vm.drafts.length ? vm.drafts[vm.drafts.length - 1] : null;
667
+ if (cur) {
668
+ cur.elements.forEach((e) => {
669
+ if (e.missing) return;
670
+ const isChild = /[a-z]$/.test(e.ref ?? "");
671
+ const groupRef = isChild ? e.ref.slice(0, -1) : null;
672
+ if (isChild && vm.expanded !== groupRef) return;
673
+ let target = null;
674
+ try {
675
+ target = document.querySelector(e.selector);
676
+ } catch {
677
+ }
678
+ if (!target) return;
679
+ const r = target.getBoundingClientRect();
680
+ place(el("div", isChild ? "marker child" : "marker"), r.left - 2, r.top - 2, r.width + 4, r.height + 4, e.ref ?? "");
681
+ });
682
+ cur.regions?.forEach((r) => {
683
+ place(el("div", "marker region"), r.rect.x - scrollX, r.rect.y - scrollY, r.rect.w, r.rect.h, r.ref ?? "");
684
+ });
685
+ }
686
+ const working = vm.locked && vm.connected;
687
+ line.hidden = !working;
688
+ if (working) {
689
+ const wbox = (cls) => {
690
+ const m = el("div", cls);
691
+ const clip = el("div", "clip");
692
+ clip.append(el("span", "sweep"));
693
+ m.append(clip);
694
+ return m;
695
+ };
696
+ for (const b of vm.sent) {
697
+ b.elements.forEach((e) => {
698
+ if (e.missing) return;
699
+ if (/[a-z]$/.test(e.ref ?? "")) return;
700
+ let target = null;
701
+ try {
702
+ target = document.querySelector(e.selector);
703
+ } catch {
704
+ }
705
+ if (!target) return;
706
+ const r = target.getBoundingClientRect();
707
+ place(wbox("wbox"), r.left - 2, r.top - 2, r.width + 4, r.height + 4, e.ref ?? "");
708
+ });
709
+ b.regions?.forEach((r) => {
710
+ place(wbox("wbox region"), r.rect.x - scrollX, r.rect.y - scrollY, r.rect.w, r.rect.h, r.ref ?? "");
711
+ });
661
712
  }
662
- if (!target) return;
663
- const r = target.getBoundingClientRect();
664
- place(el("div", isChild ? "marker child" : "marker"), r.left - 2, r.top - 2, r.width + 4, r.height + 4, e.ref ?? "");
665
- });
666
- cur.regions?.forEach((r) => {
667
- place(el("div", "marker region"), r.rect.x - scrollX, r.rect.y - scrollY, r.rect.w, r.rect.h, r.ref ?? "");
668
- });
713
+ }
669
714
  });
670
715
  }
671
716
  function flash(selectors) {
@@ -1125,6 +1170,7 @@ ${Math.round(r.width)}\xD7${Math.round(r.height)}`;
1125
1170
  agent: session?.agent ?? { status: "idle", text: "" },
1126
1171
  strategy: session ? session.strategy ?? session.detected : null,
1127
1172
  drafts: drafts ?? [],
1173
+ sent: session?.batches.filter((b) => b.status === "sent") ?? [],
1128
1174
  locked: session?.agent.status === "sent" || session?.agent.status === "working",
1129
1175
  prefs,
1130
1176
  expanded: expandedGroup
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cobro-mcp",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Co-browse for coding agents: pick elements in the browser, write a note, Send — the context lands in the agent's chat. MCP server with 6 tools.",
5
5
  "keywords": [
6
6
  "mcp",