cobro-mcp 0.10.0 → 0.10.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 +5 -0
- package/README.ko.md +3 -2
- package/README.md +3 -2
- package/dist/overlay.js +11 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,11 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.10.1] — 2026-09-24
|
|
8
|
+
### Changed
|
|
9
|
+
- The Send button is always visible; it is disabled until a draft has a note (it was hidden before).
|
|
10
|
+
- The toolbar's "view /path" link no longer repeats "Done" next to the Done chip.
|
|
11
|
+
|
|
7
12
|
## [0.10.0] — 2026-09-24
|
|
8
13
|
### Added
|
|
9
14
|
- Batches carry the page they were picked on (batches[].page), and status/done accept an optional batchId so an agent can work through several batches in order.
|
package/README.ko.md
CHANGED
|
@@ -54,7 +54,7 @@ claude mcp add -s user cobro -- npx -y cobro-mcp@latest
|
|
|
54
54
|
|
|
55
55
|
## 사용법
|
|
56
56
|
|
|
57
|
-
- **사람**: 페이지에서 `Ctrl+Shift+F`로 선택 모드(`Esc`로 해제) → 요소 클릭(드래그는 밴드 안에 완전히 든 최상위 요소들) → 메모 → **Send**. Select를 누르면 패널이 열린다(요소를 고르거나 메모만 써도 된다); Select를 다시 누르거나 Esc, 패널 헤더의 ✕를 누르면 닫히고 초안은 그대로 남는다.
|
|
57
|
+
- **사람**: 페이지에서 `Ctrl+Shift+F`로 선택 모드(`Esc`로 해제) → 요소 클릭(드래그는 밴드 안에 완전히 든 최상위 요소들) → 메모 → **Send**. Select를 누르면 패널이 열린다(요소를 고르거나 메모만 써도 된다); Select를 다시 누르거나 Esc, 패널 헤더의 ✕를 누르면 닫히고 초안은 그대로 남는다. 고른 요소마다 번호 마커가 붙는다. 여러 개면 "1: …, 2: …"로 쓴다. 요소 둘 이상 위에서 드래그하면 하나의 그룹으로 잡힌다 — 밴드가 영역(1)이 되고 안의 요소들은 1a, 1b…를 받는다. 행을 펼치면 보이거나 뺄 수 있다. 요소 하나 위 밴드는 그 요소 하나만, 빈 곳 위 밴드는 영역이 된다. 툴바(왼쪽 손잡이)와 패널(헤더)은 끌어서 옮길 수 있고, 새로고침되면 기본 위치로 돌아온다. 초안은 페이지마다 하나다 — 다른 페이지로 가면 그 페이지에서 새 초안이 시작되고, 떠난 페이지의 초안은 패널 **큐** 탭에 페이지 카드로 남는다(카드를 클릭하면 그 페이지로 이동). **Send**는 메모가 있는 모든 페이지 초안을 순서대로 보낸다(`Send · 2페이지`); 메모가 하나도 없으면 비활성이다. 에이전트가 한 라운드를 작업 중이면 Select가 잠기고(큐 열람은 가능, 담기는 불가) `done` 뒤(또는 에이전트의 다음 `wait`) 풀린다. 작업 중인 요소·영역에는 파란 스캔 테두리가, 툴바에는 흐르는 선이 표시된다(`prefers-reduced-motion`이면 정지). 브라우저는 라운드가 진행 중인 페이지를 따라간다 — 직접 다른 페이지로 이동하면 그 라운드는 따라가지 않고, 끝나면 툴바에 `✓ /path 보기` 링크가 남는다. 완료된 페이지는 큐 탭에 접힌 한 줄로 남고, 다시 담으면 정리된다. 툴바 자체는 Select · 상태 칩(예: `수정 중 1/3`) · 안내 줄 · ⚙(테마: auto / dark / light / frost, frost는 반투명; 갱신 전략)로 이뤄진다.
|
|
58
58
|
- **에이전트**: `open(url)` → `wait()` → payload의 `batches[].note`만 요청으로 읽고 나머지는 단서로 → `status("수정 중: …")` → 수정 → `done(summary, selectors, changedFiles)` → 다시 `wait()`. 끝내면 `close()`.
|
|
59
59
|
|
|
60
60
|
도구는 여섯 개로 고정이다. 관찰·조작이 더 필요하면 다른 MCP를 함께 쓴다.
|
|
@@ -165,7 +165,8 @@ window.addEventListener('cobro:done', (e) => { const { summary, changedFiles, se
|
|
|
165
165
|
|
|
166
166
|
- React 컴포넌트 이름은 dev 빌드에서만 온다. `source`(파일:행)는 dev 서버의 소스맵(React 19) 또는 `_debugSource`(React 18까지)로 복원한다 — 소스맵 없는 프로덕션 빌드는 컴포넌트 이름만 온다. 컴포넌트 라이브러리 안 요소는 라이브러리 내부가 아니라 사용자가 쓴 JSX 위치가 온다.
|
|
167
167
|
- iframe 미지원(최상위 문서만). 네이티브 modal `<dialog>`가 열려 있는 동안은 오버레이가 가려진다(라이브러리 모달은 무관).
|
|
168
|
-
- `done`의 요소 강조는 best-effort
|
|
168
|
+
- `done`의 요소 강조는 best-effort다(리로드 뒤 재생된다).
|
|
169
|
+
- 비활성화된 컨트롤(예: disabled 버튼)은 클릭을 받지 않아 클릭 픽이 부모 요소로 잡힌다 — 대신 드래그로 밴드를 씌운다.
|
|
169
170
|
- 선택 모드 단축키 `Ctrl+Shift+F`는 바꿀 수 없다. WebKit 빌드는 실제 Safari와 폰트·스크롤바가 다르다.
|
|
170
171
|
- 브라우저 프로필은 한 번에 한 세션만 쓴다 — 다른 세션이 쓰는 중이면 `open`이 "프로필 사용 중"으로 실패한다(`COBRO_PROFILE_DIR`로 따로 지정 가능).
|
|
171
172
|
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ The whole loop is the GIF at the top. No copy-paste, no "check my annotations"
|
|
|
54
54
|
|
|
55
55
|
## Usage
|
|
56
56
|
|
|
57
|
-
- **Human**: on the page, press `Ctrl+Shift+F` to toggle pick mode (`Esc` to exit) → click an element (drag picks the topmost elements fully inside the band) → write a note → **Send**. Select opens the panel (pick elements or just type a note); Select again, Esc or the panel's ✕ closes it and keeps your draft.
|
|
57
|
+
- **Human**: on the page, press `Ctrl+Shift+F` to toggle pick mode (`Esc` to exit) → click an element (drag picks the topmost elements fully inside the band) → write a note → **Send**. Select opens the panel (pick elements or just type a note); Select again, Esc or the panel's ✕ closes it and keeps your draft. Each picked element gets a numbered marker; with several, write "1: …, 2: …". Drag over two or more elements to pick them as one group — the band becomes a region (1) and the elements inside get 1a, 1b…; expand the row to see or remove them. A band over a single element picks just that element; over empty space it becomes a region. Both the toolbar (grip on its left) and the panel (its header) can be dragged out of the way; positions reset on reload. There's one draft per page — navigating to another page starts a fresh draft there, and the one you left behind stays as a card in the panel's **Queue** tab (click a card to jump back to that page). **Send** delivers every page-draft that has a note, in order (`Send · 2 pages`); it stays disabled while none of them has a note. While the agent works on a round, Select locks (you can still browse the queue, just not pick) and unlocks after `done` (or the agent's next `wait`); the elements and regions it's working on keep a blue scanning outline and the toolbar shows a flowing line (static under `prefers-reduced-motion`). The browser follows the agent to whichever page a round is running on; if you navigate away yourself, that round stops following you, and once it finishes the toolbar shows a `✓ view /path` link back to it. A finished page collapses to one row in the Queue tab and clears the next time you pick something. The toolbar itself is Select, a status chip (e.g. `Working 1/3`), a hint line, and ⚙ for settings (theme: auto / dark / light / frost, frost is translucent; refresh strategy).
|
|
58
58
|
- **Agent**: `open(url)` → `wait()` → read only `batches[].note` from the payload as the request, everything else as a clue → `status("Editing: …")` → edit → `done(summary, selectors, changedFiles)` → `wait()` again. Call `close()` to end the session.
|
|
59
59
|
|
|
60
60
|
There are exactly six fixed tools. If you need more observation or control, pair Cobro with another MCP.
|
|
@@ -165,7 +165,8 @@ window.addEventListener('cobro:done', (e) => { const { summary, changedFiles, se
|
|
|
165
165
|
|
|
166
166
|
- React component name comes from dev builds. `source` (file:line) is recovered from the dev server's source maps (React 19) or from `_debugSource` (React ≤ 18); production builds without maps report the component only. For component libraries: the location is the JSX call site in your code, not the library's internals.
|
|
167
167
|
- No iframe support (top-level document only). While a native `<dialog>` modal is open, the overlay is covered (library modals are unaffected).
|
|
168
|
-
- Element highlighting on `done` is best-effort
|
|
168
|
+
- Element highlighting on `done` is best-effort (it replays after a reload).
|
|
169
|
+
- A disabled control (e.g. a disabled button) does not receive clicks, so click-picking lands on its parent; drag a band over it instead.
|
|
169
170
|
- The pick-mode shortcut `Ctrl+Shift+F` cannot be changed. The WebKit build differs from real Safari in fonts and scrollbars.
|
|
170
171
|
- The browser profile is used by one session at a time — if another session is using it, `open` fails with "profile in use" (point `COBRO_PROFILE_DIR` elsewhere to work around it).
|
|
171
172
|
|
package/dist/overlay.js
CHANGED
|
@@ -240,7 +240,7 @@ div.queue{display:flex;flex-direction:column;gap:8px;max-height:min(45vh,320px);
|
|
|
240
240
|
.row .sends{color:var(--fg-5);font-size:11px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
241
241
|
.row .send{color:var(--fg-on-accent);background:var(--accent);border-color:var(--accent);font-weight:700;flex:none;white-space:nowrap}
|
|
242
242
|
.row .send:disabled{opacity:.4;cursor:not-allowed}
|
|
243
|
-
.row .foot{font-size:11px;color:var(--fg-4)}
|
|
243
|
+
.row .foot{font-size:11px;color:var(--fg-4);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
244
244
|
.row .foot.ok{color:var(--ok)}
|
|
245
245
|
.marker{position:fixed;border:2px solid var(--accent);border-radius:2px;pointer-events:none;box-sizing:border-box}
|
|
246
246
|
.marker.region{border-style:dashed;background:color-mix(in srgb, var(--accent) 6%, transparent)}
|
|
@@ -325,9 +325,11 @@ div.queue{display:flex;flex-direction:column;gap:8px;max-height:min(45vh,320px);
|
|
|
325
325
|
tipDrag: "\uD234\uBC14 \uC774\uB3D9",
|
|
326
326
|
sends: "\uC120\uD0DD\uC790 \xB7 \uC2A4\uD0C0\uC77C \xB7 \uC2A4\uD06C\uB9B0\uC0F7 \xB7 \uCF58\uC194",
|
|
327
327
|
tipSend: "\uC120\uD0DD\uD55C \uC694\uC18C\uC640 \uBA54\uBAA8\uB97C \uC5D0\uC774\uC804\uD2B8\uC5D0 \uC804\uC1A1",
|
|
328
|
+
tipSendLocked: "\uC5D0\uC774\uC804\uD2B8\uAC00 \uC218\uC815 \uC911 \u2014 \uC644\uB8CC \uD6C4 \uBCF4\uB0BC \uC218 \uC788\uC5B4\uC694",
|
|
329
|
+
tipSendNote: "\uBA54\uBAA8\uB97C \uC801\uC73C\uBA74 \uBCF4\uB0BC \uC218 \uC788\uC5B4\uC694",
|
|
328
330
|
tipRemove: "\uC774 \uC694\uC18C \uBE7C\uAE30",
|
|
329
331
|
cartNoNote: "\uBA54\uBAA8 \uC5C6\uC74C",
|
|
330
|
-
doneElsewhere: (path) => `\u2713
|
|
332
|
+
doneElsewhere: (path) => `\u2713 ${path} \uBCF4\uAE30`,
|
|
331
333
|
tabHere: "\uC774 \uD398\uC774\uC9C0",
|
|
332
334
|
tabQueue: "\uD050",
|
|
333
335
|
herePage: "\uC9C0\uAE08 \uBCF4\uACE0 \uC788\uB294 \uD398\uC774\uC9C0",
|
|
@@ -387,9 +389,11 @@ div.queue{display:flex;flex-direction:column;gap:8px;max-height:min(45vh,320px);
|
|
|
387
389
|
tipDrag: "Move toolbar",
|
|
388
390
|
sends: "Sends selector \xB7 styles \xB7 shot \xB7 console",
|
|
389
391
|
tipSend: "Send the selected elements and note to the agent",
|
|
392
|
+
tipSendLocked: "Agent is working \u2014 you can send after done",
|
|
393
|
+
tipSendNote: "Write a note to send",
|
|
390
394
|
tipRemove: "Remove this element",
|
|
391
395
|
cartNoNote: "No note",
|
|
392
|
-
doneElsewhere: (path) => `\u2713
|
|
396
|
+
doneElsewhere: (path) => `\u2713 view ${path}`,
|
|
393
397
|
tabHere: "This page",
|
|
394
398
|
tabQueue: "Queue",
|
|
395
399
|
herePage: "The page you're on",
|
|
@@ -870,8 +874,8 @@ div.queue{display:flex;flex-direction:column;gap:8px;max-height:min(45vh,320px);
|
|
|
870
874
|
}
|
|
871
875
|
const readyDrafts = vm.drafts.filter((b) => b.note.trim());
|
|
872
876
|
const row = el("div", "row");
|
|
877
|
+
const send = el("button", "send", readyDrafts.length >= 2 ? T.sendPages(readyDrafts.length) : "Send \u2192");
|
|
873
878
|
if (readyDrafts.length > 0) {
|
|
874
|
-
const send = el("button", "send", readyDrafts.length >= 2 ? T.sendPages(readyDrafts.length) : "Send \u2192");
|
|
875
879
|
send.title = T.tipSend;
|
|
876
880
|
send.onclick = () => {
|
|
877
881
|
closePop();
|
|
@@ -879,6 +883,8 @@ div.queue{display:flex;flex-direction:column;gap:8px;max-height:min(45vh,320px);
|
|
|
879
883
|
};
|
|
880
884
|
row.append(el("span", "sends", T.sends), send);
|
|
881
885
|
} else {
|
|
886
|
+
send.disabled = true;
|
|
887
|
+
send.title = vm.locked ? T.tipSendLocked : T.tipSendNote;
|
|
882
888
|
let footText;
|
|
883
889
|
let footOk = false;
|
|
884
890
|
if (vm.busy) footText = vm.followPaused ? T.footPaused(round.done, round.total) : T.footBusy(round.done, round.total);
|
|
@@ -886,7 +892,7 @@ div.queue{display:flex;flex-direction:column;gap:8px;max-height:min(45vh,320px);
|
|
|
886
892
|
footText = T.footAllDone(doneList.length);
|
|
887
893
|
footOk = true;
|
|
888
894
|
} else footText = T.footHint;
|
|
889
|
-
row.append(el("span", `foot${footOk ? " ok" : ""}`, footText));
|
|
895
|
+
row.append(el("span", `foot${footOk ? " ok" : ""}`, footText), send);
|
|
890
896
|
}
|
|
891
897
|
panel.append(row);
|
|
892
898
|
for (const id of [...textareas.keys()]) if (!vm.drafts.some((b) => b.id === id)) textareas.delete(id);
|
package/package.json
CHANGED