@usercase/mcp 0.2.10-next.4 → 0.2.10-next.5

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.
@@ -41,6 +41,7 @@ If important parts of the site are only reachable when signed in (a dashboard, "
41
41
  - **the sign-in cookie**: whether it has a lifetime (`maxAge`, `ttl`, `expires`) or lasts only until the browser closes
42
42
  - **how long a sign-in lasts**, in hours
43
43
  - anything that would stop a demo account: required email verification, invite-only sign-up
44
+ - **whether one account can be signed in in several browsers at the same time**: whether a new sign-in or a refresh replaces the earlier session (one active session per account, rotating refresh tokens, a session bound to the device or IP). Visitors on the same account share one saved session in separate browsers.
44
45
 
45
46
  Then decide:
46
47
  - A lasting cookie (most sites): open `login` with the default window. Google and other buttons work there.
@@ -93,7 +94,7 @@ For each person, start a `{{visitor}}` sub-agent{{spawn}} with a prompt like:
93
94
 
94
95
  > Call open_visit with person "<id>" and live this visit as that person until you leave.
95
96
 
96
- Start the whole round at once (at most 5 run at the same time). Do not give them anything else — no hints about the site, no instructions about what to find or which card to answer.
97
+ Start the whole round at once (at most 5 run at the same time) — except members: if the code shows one account cannot be used in several browsers at once, or you could not tell, never run two members on the same account at the same time: give each member an `account` in `save_people` so you know which one they use, start the next member on an account when the visit on it has ended, and run newcomers alongside. If it can be used at once, members run together like everyone else. Do not give them anything else — no hints about the site, no instructions about what to find or which card to answer.
97
98
 
98
99
  If any visitor reports the site is blocking us, stop starting new ones and tell the user.
99
100
 
package/agents/study.md CHANGED
@@ -10,6 +10,8 @@ Show the user the tasks in one short list before casting, so they know what the
10
10
 
11
11
  **The research decides what the visit is about — do not ask the user about it.** Not what the visitors should try, how far they should go, which tasks to cover or what to focus on: the participants get the research's tasks from the study panel and do what they would do. The only questions for the user are the ones the steps below always ask — demo accounts (if parts of the tasks need sign-in) and whether writes are sent — asked as those questions, in those words, and not merged with anything about the research. A task that needs a sign-in the visitors do not have is still run: what happens to a participant without an account is a result.
12
12
 
13
+ **Tasks that need a sign-in.** Read the tasks against the code: if a task can only be done signed in (following, saving, a "my" page, posting), the demo-account question is required in this run, not optional — say which task needs it when you ask. If the user has accounts, cast both members and newcomers, so the research shows what members do and what newcomers run into. If they have none, say once that those tasks will show only what newcomers run into, and go on.
14
+
13
15
  **Step 3 — cast participants for this research.** Each person is someone who really comes to this site and who would accept this research's invitation — people its purpose is about. Their `goal` is still their own reason for being on the site, in their own words; **do not write the tasks into the goal or anywhere else**. The visitors read the tasks themselves in the study panel, as real participants do — a visitor told the task by you knows more than a participant would, and the research loses its value.
14
16
  - Vary them the way real participants vary: devices, how familiar they are with the site, patience, how carefully they read. Some will finish every task, some will get stuck — that is what the research is for.
15
17
  - Give each person a `landing` page where the research's invitation would meet them: the page the first task starts from, if the tasks or the code make it clear; otherwise where they would arrive on their own.
package/mcp/hub.js CHANGED
@@ -29,6 +29,8 @@ const report = require("./report.js");
29
29
 
30
30
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
31
31
  /** 리서치가 아직 진행 중인 위젯 상태(core StateManager WidgetState). 이 밖이면 과제가 끝난 것이다 */
32
+ /** 패널을 기다리는 가장 긴 시간 — 과제의 실패 시간은 대개 5분(대시보드 기본) */
33
+ const STUDY_WAIT_MS = 5 * 60 * 1000;
32
34
  const STUDY_ACTIVE = new Set(["consent", "loading", "testing", "timeout", "survey", "next", "submit"]);
33
35
 
34
36
  /**
@@ -427,7 +429,8 @@ class Hub {
427
429
  external,
428
430
  study: research
429
431
  ? {
430
- press: (k) => study.press(page, k),
432
+ // wait — 과제를 그만 두고 패널을 기다린다. 위젯 단추가 아니라 도구가 기다린다(그동안 방문자는 아무것도 안 한다)
433
+ press: (k) => (k === "wait" ? this.studyWait(rec) : study.press(page, k)),
431
434
  // 과제 질문·시간 초과 창이 페이지를 덮고 있나 — 그 사이 조작은 페이지에 닿지 않는다
432
435
  blocking: async () => {
433
436
  const w = study.isSurveyUrl(page.url()) ? null : await study.readStudy(page);
@@ -459,7 +462,8 @@ class Hub {
459
462
  "",
460
463
  "A small invitation popped up asking you to take part in a short study on this site, and you agreed: you accepted it and allowed your screen to be recorded.",
461
464
  "The study panel in the corner of the screen now shows your first task. Do the tasks as yourself, on the site, in your own way — the panel knows when a task is done and moves on by itself.",
462
- "If you get stuck on a task, behave as you would: keep trying, use the panel's Skip when it offers one, or leave. The study may ask you a few questions along the way; answer them with answer_card.",
465
+ "You agreed to take part, so you stay with the study until its tasks are done — you do not leave the site in the middle of it over a small thing. The study may ask you a few questions along the way; answer them with answer_card.",
466
+ "If you get stuck on a task, keep trying in your own way for as long as you would. When you would give up on that task, wait on the study panel (it is in the list): studies often offer a way to give up on a task after a while, and then you go on to the next task. Leave in the middle only if you really would — the study never offers a way on, or something about you or your moment makes you stop.",
463
467
  );
464
468
  if (!sdk.ready) lines.push("(note for whoever runs this: the Usercase SDK did not start on this page — this visit may not be recorded)");
465
469
  lines.push("", await this.screen(rec));
@@ -477,6 +481,8 @@ class Hub {
477
481
  if (look.card) return renderCard(look.card);
478
482
  // 과제 건너뛰기는 위젯 단추다. 화면 목록 끝에 붙인다 — 누르면 Visit 이 위젯을 누른다
479
483
  if (st && st.skip && !look.view.dialog) look.view.items.push({ i: look.view.items.length, label: `${st.skip} (in the study panel — gives up on this task)`, where: "study panel, corner of the screen", study: "skip" });
484
+ // 아직 건너뛸 수 없는 과제 — 그만 두고 패널을 기다릴 수 있다. 실패 시간이 있는 과제면 그 사이 패널이 포기를 받아 준다
485
+ else if (st && st.panel && !look.view.dialog) look.view.items.push({ i: look.view.items.length, label: "Wait on the study panel (stop trying this task for now)", where: "study panel, corner of the screen", study: "wait" });
480
486
  // 브라우저 창(confirm 등)이 떠 있다. 페이지는 멈춰 있다 — 아이콘 그림·위치는 안 본다
481
487
  if (look.view.dialog) {
482
488
  this.pictures.set(rec.id, null);
@@ -557,6 +563,10 @@ class Hub {
557
563
  }
558
564
  st.lastTaskKey = key;
559
565
  st.lastTask = s.task.title;
566
+ if (st.waitNote) {
567
+ note = note ? `${note} ${st.waitNote}` : st.waitNote;
568
+ st.waitNote = null;
569
+ }
560
570
  return { panel: renderStudyPanel(s.task), skip: s.task.skip, note };
561
571
  }
562
572
  // 과제가 다 끝났다. 끝난 뒤 설문이 있으면 SDK 가 새 탭으로 열고, 그 탭은 이 탭으로 옮겨 온다(open 의 새 탭 처리)
@@ -574,6 +584,20 @@ class Hub {
574
584
  return null;
575
585
  }
576
586
 
587
+ /**
588
+ * 과제를 그만 두고 패널을 기다린다 — 실패 시간이 있는 과제면 SDK 가 "어렵나요?" 창(timeout)을 띄우고 건너뛰기를 열어 준다.
589
+ * 실패 시간이 없는 과제는 아무것도 안 온다. 다 기다리고도 그대로면 방문자에게 그렇게 알린다(그다음은 방문자가 정한다).
590
+ * 막힌 참여자가 패널이 열어 주기 전에 사이트를 떠나, 30명 중 27명이 과제 2에서 기록 없이 사라졌다(10/30 라이브 bluetags)
591
+ */
592
+ async studyWait(rec) {
593
+ const st = rec.study;
594
+ const s = await study.waitState(rec.page, ["timeout", "survey", "next", "submit", "done", "complete", "idle"], STUDY_WAIT_MS);
595
+ if (!s || s.state === "testing") {
596
+ st.waited = (st.waited || 0) + 1;
597
+ st.waitNote = "(You waited about five minutes on the study panel. It has not offered a way to give up on this task yet.)";
598
+ }
599
+ }
600
+
577
601
  /** 과제 질문·시간 초과 창에 답한다. 참여하기로 한 사람이라 닫지 않는다 — 비워 두고 넘기는 건 된다(필수가 아니면) */
578
602
  async studyAnswer(rec, decision) {
579
603
  const p = rec.studyPending;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usercase/mcp",
3
- "version": "0.2.10-next.4",
3
+ "version": "0.2.10-next.5",
4
4
  "description": "Virtual users that browse your website and tell you what they thought — an MCP server for Claude Code",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://usercase.io",