pageqa 0.1.0 → 0.2.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jev.js","sourceRoot":"","sources":["../src/jev.ts"],"names":[],"mappings":"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"}
package/dist/llm.js CHANGED
@@ -2,12 +2,12 @@ import { createModels, createProvider } from "@earendil-works/pi-ai";
2
2
  import * as openaiCompletions from "@earendil-works/pi-ai/api/openai-completions";
3
3
  import { loadConfig } from "./config.js";
4
4
  /**
5
- * LLM 后端:基于 @earendil-works/pi-ai 构造一个指向 CodeBuddy 本地反代的自定义 provider。
5
+ * LLM 后端:基于 @earendil-works/pi-ai 构造一个指向可配置的 OpenAI 兼容端点的自定义 provider。
6
6
  *
7
7
  * 配置优先级(高 -> 低):环境变量 PAGEQA_LLM_* > 用户配置文件(~/.pageqa/config.json) > 内置默认值。
8
- * 首次运行会自动在用户主目录创建配置文件,便于用户修改模型/反代地址/密钥。
8
+ * 首次运行会自动在用户主目录创建配置文件,便于用户修改模型/端点地址/密钥。
9
9
  */
10
- const PROVIDER_ID = "codebuddy";
10
+ const PROVIDER_ID = "pageqa";
11
11
  const MODELS = [
12
12
  { id: "hunyuan-2.0-instruct", name: "Hunyuan 2.0 Instruct", contextWindow: 32000, maxOutput: 64000 },
13
13
  { id: "hy3", name: "Hy3", contextWindow: 192000, maxOutput: 64000 },
@@ -16,7 +16,7 @@ const MODELS = [
16
16
  /** 构造一个静态解析的 ApiKeyAuth(避免交互式 env 探测)。 */
17
17
  function staticApiKeyAuth(apiKey, baseUrl) {
18
18
  return {
19
- name: "CodeBuddy Proxy",
19
+ name: "OpenAI Compatible",
20
20
  resolve: async () => ({ auth: { apiKey, baseUrl }, source: "static" }),
21
21
  };
22
22
  }
@@ -28,7 +28,7 @@ export function createLlmBackend() {
28
28
  const models = createModels();
29
29
  const provider = createProvider({
30
30
  id: PROVIDER_ID,
31
- name: "CodeBuddy (本地反代)",
31
+ name: "OpenAI Compatible (自定义端点)",
32
32
  auth: { apiKey: staticApiKeyAuth(DEFAULT_API_KEY, DEFAULT_BASE_URL) },
33
33
  models: MODELS.map((m) => ({
34
34
  id: m.id,
@@ -55,7 +55,7 @@ export function createLlmBackend() {
55
55
  models.setProvider(provider);
56
56
  const model = models.getModel(PROVIDER_ID, DEFAULT_MODEL);
57
57
  if (!model) {
58
- throw new Error(`未找到模型 ${DEFAULT_MODEL}(provider=${PROVIDER_ID})。请确认 CodeBuddy 反代可用。`);
58
+ throw new Error(`未找到模型 ${DEFAULT_MODEL}(provider=${PROVIDER_ID})。请检查 ~/.pageqa/config.json 中的 model 与 baseUrl 配置。`);
59
59
  }
60
60
  return { models, model };
61
61
  }
package/dist/llm.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"llm.js","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAwB,MAAM,uBAAuB,CAAC;AAC3F,OAAO,KAAK,iBAAiB,MAAM,8CAA8C,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;GAKG;AAEH,MAAM,WAAW,GAAG,WAAW,CAAC;AAShC,MAAM,MAAM,GAA2B;IACrC,EAAE,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,sBAAsB,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;IACpG,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;IACnE,EAAE,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,qBAAqB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE;CACzG,CAAC;AAEF,0CAA0C;AAC1C,SAAS,gBAAgB,CAAC,MAAc,EAAE,OAAe;IACvD,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;KACvE,CAAC;AACJ,CAAC;AAOD,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAAC;IACrC,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC;IACnC,MAAM,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC;IAChC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,cAAc,CAAC;QAC9B,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE,EAAE,MAAM,EAAE,gBAAgB,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAE;QACrE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,oBAAoB;YACzB,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,gBAAgB;YACzB,KAAK,EAAE,CAAC,MAAM,CAAC;YACf,SAAS,EAAE,KAAK;YAChB,aAAa,EAAE,CAAC,CAAC,aAAa;YAC9B,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;YAC1D,MAAM,EAAE;gBACN,aAAa,EAAE,KAAK;gBACpB,qBAAqB,EAAE,KAAK;gBAC5B,uBAAuB,EAAE,KAAK;gBAC9B,cAAc,EAAE,YAAY;gBAC5B,0BAA0B,EAAE,KAAK;aAClC;SACF,CAAC,CAAC;QACH,GAAG,EAAE,iBAAiB;KACvB,CAAC,CAAC;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAE7B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,SAAS,aAAa,aAAa,WAAW,uBAAuB,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAwB,MAAM,uBAAuB,CAAC;AAC3F,OAAO,KAAK,iBAAiB,MAAM,8CAA8C,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;GAKG;AAEH,MAAM,WAAW,GAAG,QAAQ,CAAC;AAS7B,MAAM,MAAM,GAAqB;IAC/B,EAAE,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,sBAAsB,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;IACpG,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;IACnE,EAAE,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,qBAAqB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE;CACzG,CAAC;AAEF,0CAA0C;AAC1C,SAAS,gBAAgB,CAAC,MAAc,EAAE,OAAe;IACvD,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;KACvE,CAAC;AACJ,CAAC;AAOD,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAAC;IACrC,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC;IACnC,MAAM,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC;IAChC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,cAAc,CAAC;QAC9B,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,2BAA2B;QACjC,IAAI,EAAE,EAAE,MAAM,EAAE,gBAAgB,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAE;QACrE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,oBAAoB;YACzB,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,gBAAgB;YACzB,KAAK,EAAE,CAAC,MAAM,CAAC;YACf,SAAS,EAAE,KAAK;YAChB,aAAa,EAAE,CAAC,CAAC,aAAa;YAC9B,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;YAC1D,MAAM,EAAE;gBACN,aAAa,EAAE,KAAK;gBACpB,qBAAqB,EAAE,KAAK;gBAC5B,uBAAuB,EAAE,KAAK;gBAC9B,cAAc,EAAE,YAAY;gBAC5B,0BAA0B,EAAE,KAAK;aAClC;SACF,CAAC,CAAC;QACH,GAAG,EAAE,iBAAiB;KACvB,CAAC,CAAC;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAE7B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,SAAS,aAAa,aAAa,WAAW,oDAAoD,CACnG,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC"}
package/dist/report.d.ts CHANGED
@@ -14,3 +14,5 @@ export interface TestReport {
14
14
  * 并用「断言「X」:成立。证据...」句式。无法解析时降级为基于 PASS/FAIL 关键字的整体判断。
15
15
  */
16
16
  export declare function buildReport(input: string, transcript: string): TestReport;
17
+ /** 统计用例(自然语言测试步骤)中的断言数量,用于校验执行完整性。 */
18
+ export declare function countAssertions(script: string): number;
package/dist/report.js CHANGED
@@ -10,32 +10,83 @@ export function buildReport(input, transcript) {
10
10
  }
11
11
  else {
12
12
  // 无结构化断言:依据关键字与「不成立/失败」判定
13
- const lowered = transcript.toLowerCase();
14
13
  const negative = /不成立|未找到|失败|不存在|not found|fail|missing/.test(transcript);
15
14
  status = negative ? "fail" : "pass";
16
15
  }
16
+ // 完整性校验:用例里写了 N 条断言,就应当看到 N 条结果;
17
+ // 少了解析结果说明 agent 只跑了其中一部分(长流程最容易半途结束)。
18
+ const expected = countAssertions(input);
19
+ if (expected > 0 && assertions.length < expected) {
20
+ status = "fail";
21
+ assertions.push({
22
+ expectation: `用例中的断言全部执行(实际 ${assertions.length}/${expected})`,
23
+ verdict: "fail",
24
+ evidence: "解析到的断言少于用例中的断言数量,疑似步骤未执行完就结束",
25
+ });
26
+ }
27
+ // agent 自报的步骤进度未跑满,同样判失败。
28
+ const progress = parseProgress(transcript);
29
+ if (progress && progress.done < progress.total) {
30
+ status = "fail";
31
+ assertions.push({
32
+ expectation: `全部步骤执行完成(${progress.done}/${progress.total})`,
33
+ verdict: "fail",
34
+ evidence: "agent 自报的步骤完成度不足",
35
+ });
36
+ }
17
37
  const summary = extractSummary(transcript);
18
38
  return { status, assertions, summary, transcript };
19
39
  }
40
+ /** 统计用例(自然语言测试步骤)中的断言数量,用于校验执行完整性。 */
41
+ export function countAssertions(script) {
42
+ return (script.match(/断言/g) ?? []).length;
43
+ }
44
+ /** 解析 agent 结尾的进度声明「步骤完成:M/N」。 */
45
+ function parseProgress(text) {
46
+ const m = /步骤完成\s*[::]\s*(\d+)\s*[//]\s*(\d+)/.exec(text);
47
+ if (!m)
48
+ return null;
49
+ const done = Number(m[1]);
50
+ const total = Number(m[2]);
51
+ if (!Number.isFinite(done) || !Number.isFinite(total) || total <= 0)
52
+ return null;
53
+ return { done, total };
54
+ }
20
55
  function parseAssertions(text) {
21
56
  const results = [];
22
- // 匹配两种常见句式:
23
- // 断言「X」:成立/不成立。证据...
57
+ // 预处理:
58
+ // 1) 去掉 markdown 加粗标记(agent 常输出「…:**成立**」)
59
+ // 2) 把「成立/不成立」前的换行折回同一行
60
+ const cleaned = text
61
+ .replace(/\*\*|__/g, "")
62
+ .replace(/[ \t]*\n[ \t]*(?=(?:成立|不成立))/g, "");
63
+ // 匹配两种常见句式(描述里可含「」/引号等标点):
64
+ // 断言 X:成立/不成立。证据...
24
65
  // 断言「X」成立。证据...
25
- const re = /断言[「"']?([^」"']+?)[""」]?\s*(?:[::]\s*)?(成立|不成立)/g;
66
+ const re = /断言\s*(.+?)\s*(?:[::]\s*)?(不成立|成立)/g;
26
67
  let m;
27
- while ((m = re.exec(text)) !== null) {
28
- const expectation = m[1].trim();
68
+ while ((m = re.exec(cleaned)) !== null) {
69
+ const expectation = stripEdges(m[1]);
29
70
  const verdict = m[2] === "成立" ? "pass" : "fail";
30
- const after = text.slice(m.index + m[0].length).split("\n")[0].trim();
31
- const evidence = after.startsWith("。") ? after.slice(1).trim() : after;
71
+ const after = cleaned.slice(m.index + m[0].length).split("\n")[0];
72
+ const evidence = stripEdges(after);
32
73
  results.push({ expectation, verdict, evidence: evidence || undefined });
33
74
  }
34
75
  return results;
35
76
  }
77
+ /** 去掉首尾的连接符/标点噪声(agent 常写「…:**成立**,证据…」「…」——成立)。 */
78
+ function stripEdges(text) {
79
+ return text
80
+ .replace(/^[\s,,。、;;::]+/, "")
81
+ .replace(/[\s,,。、;;::\-—]+$/, "")
82
+ .trim();
83
+ }
36
84
  function extractSummary(text) {
37
85
  // 取最后一段非空文本作为摘要
38
- const paras = text.split("\n").map((l) => l.trim()).filter(Boolean);
86
+ const paras = text
87
+ .split("\n")
88
+ .map((l) => l.trim())
89
+ .filter(Boolean);
39
90
  return paras.at(-1) ?? "";
40
91
  }
41
92
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,UAAkB;IAC3D,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAE/C,IAAI,MAAuB,CAAC;IAC5B,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,0BAA0B;QAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,uCAAuC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1E,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACtC,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC3C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,YAAY;IACZ,uBAAuB;IACvB,kBAAkB;IAClB,MAAM,EAAE,GAAG,kDAAkD,CAAC;IAC9D,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,IAAI,SAAS,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,gBAAgB;IAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,UAAkB;IAC3D,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAE/C,IAAI,MAAuB,CAAC;IAC5B,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,uCAAuC,CAAC,IAAI,CAC3D,UAAU,CACX,CAAC;QACF,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACtC,CAAC;IAED,iCAAiC;IACjC,uCAAuC;IACvC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,QAAQ,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QACjD,MAAM,GAAG,MAAM,CAAC;QAChB,UAAU,CAAC,IAAI,CAAC;YACd,WAAW,EAAE,iBAAiB,UAAU,CAAC,MAAM,IAAI,QAAQ,GAAG;YAC9D,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,8BAA8B;SACzC,CAAC,CAAC;IACL,CAAC;IAED,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC/C,MAAM,GAAG,MAAM,CAAC;QAChB,UAAU,CAAC,IAAI,CAAC;YACd,WAAW,EAAE,YAAY,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,KAAK,GAAG;YAC3D,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,kBAAkB;SAC7B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC3C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACrD,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC;AAED,kCAAkC;AAClC,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,CAAC,GAAG,oCAAoC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,OAAO;IACP,6CAA6C;IAC7C,0BAA0B;IAC1B,MAAM,OAAO,GAAG,IAAI;SACjB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;IAChD,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,MAAM,EAAE,GAAG,oCAAoC,CAAC;IAChD,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACvC,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,IAAI,SAAS,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,oDAAoD;AACpD,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI;SACR,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;SAC7B,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,gBAAgB;IAChB,MAAM,KAAK,GAAG,IAAI;SACf,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,19 @@
1
+ # GitHub 仓库 Star 用例:klren0312/pageqa
2
+
3
+ > 本文件是 pageqa 的自然语言测试脚本。`# ` 标题与本节说明会被忽略,只有 `## ` 场景下的内容会被执行。
4
+ > 前置:bsk daemon 已连接一个**已登录 GitHub** 的真实浏览器;未登录时 Star 会跳转登录页,G2 将 FAIL。
5
+
6
+ ## G1 打开仓库页并校验内容
7
+
8
+ 打开 https://github.com/klren0312/pageqa
9
+ 读取页面内容
10
+ 断言标题包含 pageqa
11
+ 断言页面包含 klren0312/pageqa
12
+
13
+ ## G2 为仓库点 Star(幂等)
14
+
15
+ 打开 https://github.com/klren0312/pageqa
16
+ 读取页面内容,定位页面右上角的星标按钮(当前显示为「Star」或「Starred」)
17
+ 如果星标按钮显示「Star」,点击它并等待 2 秒
18
+ 如果星标按钮已经显示「Starred」,跳过点击,直接进入断言
19
+ 断言星标按钮当前显示为「Starred」
package/examples/smoke.md CHANGED
@@ -10,6 +10,3 @@
10
10
 
11
11
  ## A3 失败场景(断言不存在文本)
12
12
  打开 https://example.com 并断言页面包含 'THIS_TEXT_SHOULD_NOT_EXIST_XYZ'
13
-
14
- > 说明:自然语言意图由 pi-agent-core 驱动的 agent 解析为浏览器操作步骤,并经 browserskill(bsk)连接真实浏览器执行。
15
- > 默认 LLM 后端为 CodeBuddy 本地反代(混元),无需官网 Key。
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "pageqa",
3
- "version": "0.1.0",
4
- "description": "用自然语言驱动的页面测试 agent:基于 pi-agent-core 编排 + browserskill 驱动真实浏览器,经 CodeBuddy 反代(混元)实现免 Key 自然语言测试。",
3
+ "version": "0.2.2",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/klren0312/pageqa.git"
7
+ },
8
+ "description": "用自然语言驱动的页面 QA agent:pi-agent-core 编排测试步骤,browserskill(bsk) 驱动真实浏览器执行,LLM 端点可配置(OpenAI 兼容);输出文本/JSON 报告与可直接接入 CI 的退出码。",
5
9
  "type": "module",
6
10
  "bin": {
7
11
  "pageqa": "dist/index.js"
@@ -12,6 +16,7 @@
12
16
  "start": "node dist/index.js",
13
17
  "pretest": "npm run build",
14
18
  "test": "node --test tests/smoke.test.mjs",
19
+ "test:unit": "npm run build && node --test tests/report.test.mjs",
15
20
  "prepublishOnly": "npm run build"
16
21
  },
17
22
  "files": [