@nextclaw/x-harness 0.1.1 → 0.2.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.
Files changed (80) hide show
  1. package/LICENSE +231 -6
  2. package/README.md +15 -1
  3. package/SOURCE.md +9 -0
  4. package/cli/main.js +232 -200
  5. package/dist/api.d.ts +56 -2
  6. package/dist/api.js +130 -79
  7. package/dist/boundary.js +1 -0
  8. package/dist/browser-common.d.ts +11 -0
  9. package/dist/browser-common.js +34 -18
  10. package/dist/browser-dom-capabilities.d.ts +7 -2
  11. package/dist/browser-dom-capabilities.js +123 -102
  12. package/dist/browser-dom-dependencies.js +1 -0
  13. package/dist/browser-dom-editing.d.ts +20 -2
  14. package/dist/browser-dom-editing.js +148 -116
  15. package/dist/browser-dom-navigation.d.ts +11 -2
  16. package/dist/browser-dom-navigation.js +66 -50
  17. package/dist/browser-dom-submission.d.ts +6 -1
  18. package/dist/browser-dom-submission.js +37 -18
  19. package/dist/browser-dom.d.ts +13 -1
  20. package/dist/browser-dom.js +113 -66
  21. package/dist/browser-native.d.ts +14 -1
  22. package/dist/browser-native.js +161 -128
  23. package/dist/creator-native.d.ts +3 -0
  24. package/dist/creator-native.js +113 -0
  25. package/dist/diagnostics.d.ts +11 -0
  26. package/dist/diagnostics.js +10 -0
  27. package/dist/growth-batch.d.ts +6 -3
  28. package/dist/growth-batch.js +157 -135
  29. package/dist/growth-dependencies.js +1 -0
  30. package/dist/growth-execution.d.ts +8 -2
  31. package/dist/growth-execution.js +68 -37
  32. package/dist/growth-parallel.d.ts +6 -2
  33. package/dist/growth-parallel.js +78 -47
  34. package/dist/growth-plan.d.ts +8 -3
  35. package/dist/growth-plan.js +45 -23
  36. package/dist/growth-policy.d.ts +11 -2
  37. package/dist/growth-policy.js +80 -53
  38. package/dist/growth-publishing.d.ts +7 -2
  39. package/dist/growth-publishing.js +72 -46
  40. package/dist/growth-reading.d.ts +6 -2
  41. package/dist/growth-reading.js +47 -25
  42. package/dist/growth-recovery.d.ts +7 -4
  43. package/dist/growth-recovery.js +177 -148
  44. package/dist/growth-state.d.ts +10 -2
  45. package/dist/growth-state.js +67 -30
  46. package/dist/growth-tasks.d.ts +19 -16
  47. package/dist/growth-tasks.js +153 -90
  48. package/dist/growth.d.ts +25 -1
  49. package/dist/growth.js +207 -124
  50. package/dist/platform-capabilities.d.ts +6 -2
  51. package/dist/platform-capabilities.js +18 -8
  52. package/dist/platform-collections.d.ts +10 -3
  53. package/dist/platform-collections.js +62 -35
  54. package/dist/platform-dependencies.js +1 -0
  55. package/dist/platform-diagnostics.d.ts +7 -2
  56. package/dist/platform-diagnostics.js +31 -19
  57. package/dist/platform-observation.d.ts +10 -2
  58. package/dist/platform-observation.js +44 -23
  59. package/dist/platform-targets.d.ts +10 -3
  60. package/dist/platform-targets.js +39 -14
  61. package/dist/platform-writing.d.ts +10 -2
  62. package/dist/platform-writing.js +63 -32
  63. package/dist/platform.d.ts +22 -1
  64. package/dist/platform.js +120 -52
  65. package/dist/readers-ax-host.d.ts +11 -1
  66. package/dist/readers-ax-host.js +108 -99
  67. package/dist/readers-ax-program.js +5 -0
  68. package/dist/readers-ax-tree.js +1 -0
  69. package/dist/readers-cli.js +79 -0
  70. package/dist/readers.js +9 -0
  71. package/dist/round-state.js +18 -1
  72. package/dist/store.d.ts +22 -4
  73. package/dist/store.js +173 -151
  74. package/dist/types.js +1 -0
  75. package/generated/observation.mjs +1 -1
  76. package/package.json +23 -9
  77. package/skill/SKILL.md +2 -2
  78. package/skill/references/reads.md +1 -1
  79. package/skill/references/recovery.md +4 -4
  80. package/skill/references/setup.md +1 -1
package/dist/api.js CHANGED
@@ -1,13 +1,34 @@
1
1
  import { createGrowthHarness } from "./growth.js";
2
2
  import { readResult, decisions, diagnostic, stableReason } from "./results.js";
3
- export function createBusinessHarness(dependencies) {
4
- const { store } = dependencies;
5
- const core = createGrowthHarness(dependencies);
6
- const readCache = new Map();
7
- // All public operations share the same error boundary. Full errors remain local proof.
8
- async function invoke(operation, args) {
3
+ export class BusinessHarness {
4
+ #store;
5
+ #core;
6
+ #readCache;
7
+ constructor(dependencies) {
8
+ this.verifyFollow = this.verifyFollow.bind(this);
9
+ this.followBatch = this.followBatch.bind(this);
10
+ this.verifyPublishedPost = this.verifyPublishedPost.bind(this);
11
+ this.verifySubmission = this.verifySubmission.bind(this);
12
+ this.followOne = this.followOne.bind(this);
13
+ this.replyToPost = this.replyToPost.bind(this);
14
+ this.publishPost = this.publishPost.bind(this);
15
+ this.runGrowthRound = this.runGrowthRound.bind(this);
16
+ this.inspectRound = this.inspectRound.bind(this);
17
+ this.inspectAccount = this.inspectAccount.bind(this);
18
+ this.readFeedback = this.readFeedback.bind(this);
19
+ this.readPerson = this.readPerson.bind(this);
20
+ this.readPost = this.readPost.bind(this);
21
+ this.searchSources = this.searchSources.bind(this);
22
+ this.readBookmarks = this.readBookmarks.bind(this);
23
+ this.readCreator = this.readCreator.bind(this);
24
+ const { store } = dependencies;
25
+ this.#store = store;
26
+ this.#core = createGrowthHarness(dependencies);
27
+ this.#readCache = new Map();
28
+ }
29
+ async invoke(operation, args) {
9
30
  try {
10
- const raw = await core[operation](args);
31
+ const raw = await this.#core[operation](args);
11
32
  // Legacy core decisions can contain a human error without a diagnostic proof.
12
33
  // Expose a bounded recovery route; consumers never need implementation source.
13
34
  const errors = [
@@ -18,7 +39,7 @@ export function createBusinessHarness(dependencies) {
18
39
  ]),
19
40
  ].filter((reason) => typeof reason === "string" && stableReason(reason) !== reason);
20
41
  if (errors.length) {
21
- const evidenceRef = await store.recordProof({
42
+ const evidenceRef = await this.#store.recordProof({
22
43
  operation,
23
44
  error: errors[0],
24
45
  ...(errors.length > 1 ? { errors } : {}),
@@ -50,7 +71,10 @@ export function createBusinessHarness(dependencies) {
50
71
  const message = error instanceof Error ? error.message : String(error);
51
72
  let evidenceRef;
52
73
  try {
53
- evidenceRef = await store.recordProof({ operation, error: message });
74
+ evidenceRef = await this.#store.recordProof({
75
+ operation,
76
+ error: message,
77
+ });
54
78
  }
55
79
  catch {
56
80
  /* Evidence failure is explicit below. */
@@ -78,7 +102,7 @@ export function createBusinessHarness(dependencies) {
78
102
  };
79
103
  }
80
104
  }
81
- async function read(operation, args = {}, mode = "receipt") {
105
+ async read(operation, args = {}, mode = "receipt") {
82
106
  if (!["receipt", "decision", "delta"].includes(mode))
83
107
  return {
84
108
  status: "needsDecision",
@@ -86,7 +110,7 @@ export function createBusinessHarness(dependencies) {
86
110
  reason: "read-mode-invalid",
87
111
  };
88
112
  // Always collect fresh evidence once. Projection, not a second browser call, chooses output.
89
- const raw = await invoke(operation, { ...args, mode: "decision" });
113
+ const raw = await this.invoke(operation, { ...args, mode: "decision" });
90
114
  const output = readResult(operation, raw, mode);
91
115
  if (mode === "receipt")
92
116
  return output;
@@ -101,11 +125,11 @@ export function createBusinessHarness(dependencies) {
101
125
  continue;
102
126
  }
103
127
  const key = JSON.stringify([operation, id]), value = JSON.stringify(entry);
104
- if (readCache.get(key) === value)
128
+ if (this.#readCache.get(key) === value)
105
129
  unchangedIds.push(id);
106
130
  else
107
131
  changed.push(entry);
108
- readCache.set(key, value);
132
+ this.#readCache.set(key, value);
109
133
  }
110
134
  // Creator metadata changes independently from the post collection.
111
135
  if (operation === "readCreator") {
@@ -114,9 +138,9 @@ export function createBusinessHarness(dependencies) {
114
138
  continue;
115
139
  const key = JSON.stringify([operation, name, args.handle]);
116
140
  const value = JSON.stringify(output[name], (k, v) => k === "observedAt" ? undefined : v);
117
- if (mode === "delta" && readCache.get(key) === value)
141
+ if (mode === "delta" && this.#readCache.get(key) === value)
118
142
  delete output[name];
119
- readCache.set(key, value);
143
+ this.#readCache.set(key, value);
120
144
  }
121
145
  }
122
146
  // A decision has delivered complete evidence and seeds the next delta.
@@ -133,8 +157,8 @@ export function createBusinessHarness(dependencies) {
133
157
  output.unchangedIds = unchangedIds;
134
158
  return output;
135
159
  }
136
- async function compactRound(operation, args) {
137
- const raw = await invoke(operation, args);
160
+ async compactRound(operation, args) {
161
+ const raw = await this.invoke(operation, args);
138
162
  const out = {
139
163
  status: raw.status,
140
164
  taskId: args.taskId,
@@ -181,11 +205,11 @@ export function createBusinessHarness(dependencies) {
181
205
  };
182
206
  return out;
183
207
  }
184
- async function single(operation, args, selector) {
185
- const raw = await invoke(operation, args);
208
+ async single(operation, args, selector) {
209
+ const raw = await this.invoke(operation, args);
186
210
  let snapshot;
187
211
  try {
188
- snapshot = await store.load();
212
+ snapshot = await this.#store.load();
189
213
  }
190
214
  catch {
191
215
  return {
@@ -246,63 +270,90 @@ export function createBusinessHarness(dependencies) {
246
270
  out.diagnostic = d;
247
271
  return out;
248
272
  }
249
- return {
250
- readCreator: (args) => read("readCreator", args, args.mode),
251
- readBookmarks: (args) => read("readBookmarks", args, args.mode),
252
- searchSources: (args) => read("searchSources", args, args.mode),
253
- readPost: ({ target, mode }) => read("readPost", target, mode),
254
- readPerson: ({ target, mode }) => read("readPerson", target, mode),
255
- readFeedback: (args) => read("readFeedback", args, args.mode),
256
- inspectAccount: (args = {}) => read("inspectAccount", args, args.mode),
257
- inspectRound: (args) => compactRound("inspectRound", args),
258
- runGrowthRound: (args) => compactRound("runGrowthRound", args),
259
- publishPost: (args) => single("publishPost", args, (a) => a.kind === "original" && a.draftPath === args.draftPath),
260
- replyToPost: (args) => single("replyToPost", args, (a) => a.kind === "reply" &&
261
- a.postId === args.postId &&
262
- a.text === args.text),
263
- followOne: (args) => single("followOne", args, (a) => a.kind === "follow" &&
264
- a.handle?.toLowerCase() === args.handle.toLowerCase()),
265
- verifySubmission: (args) => single("verifySubmission", args, (a) => a.id === args.actionId),
266
- verifyPublishedPost: (args) => single("verifyPublishedPost", args, (a) => a.kind === "original" && a.draftPath === args.draftPath),
267
- followBatch: async (args) => {
268
- const raw = await invoke("followBatch", args);
269
- const output = {
270
- status: raw.status ?? (raw.mayEnd ? "verified" : "needsDecision"),
271
- taskId: args.taskId,
272
- planned: raw.planned ?? args.handles.length,
273
- attempted: raw.attempted ?? 0,
274
- verified: raw.verifiedThisCall ?? 0,
275
- unknown: raw.unknownInBatch ?? 0,
276
- remaining: raw.remaining ?? args.handles.length,
277
- mayEnd: raw.mayEnd === true,
278
- };
279
- if (raw.batchId)
280
- output.batchId = raw.batchId;
281
- if (raw.evidenceRef)
282
- output.evidenceRef = raw.evidenceRef;
283
- const d = diagnostic(raw.diagnostic);
284
- if (d)
285
- output.diagnostic = d;
286
- const issues = decisions(raw.decision);
287
- if (raw.reason)
288
- issues.push({ reason: raw.reason, status: "needsDecision" });
289
- if (raw.missing)
290
- issues.push({ missing: raw.missing });
291
- if (issues.length)
292
- output.decision = issues;
293
- return output;
294
- },
295
- verifyFollow: async (args) => {
296
- const raw = await invoke("verifyFollow", {
297
- ...args,
298
- mode: args.mode ?? "receipt",
299
- });
300
- const out = readResult("verifyFollow", raw, "receipt");
301
- out.handle = args.handle;
302
- out.verified = raw.verified === true;
303
- if (args.mode === "decision" && raw.observation)
304
- out.person = readResult("readPerson", raw.observation, "decision").person;
305
- return out;
306
- },
307
- };
273
+ readCreator(args) {
274
+ return this.read("readCreator", args, args.mode);
275
+ }
276
+ readBookmarks(args) {
277
+ return this.read("readBookmarks", args, args.mode);
278
+ }
279
+ searchSources(args) {
280
+ return this.read("searchSources", args, args.mode);
281
+ }
282
+ readPost({ target, mode, }) {
283
+ return this.read("readPost", target, mode);
284
+ }
285
+ readPerson({ target, mode, }) {
286
+ return this.read("readPerson", target, mode);
287
+ }
288
+ readFeedback(args) {
289
+ return this.read("readFeedback", args, args.mode);
290
+ }
291
+ inspectAccount(args = {}) {
292
+ return this.read("inspectAccount", args, args.mode);
293
+ }
294
+ inspectRound(args) {
295
+ return this.compactRound("inspectRound", args);
296
+ }
297
+ runGrowthRound(args) {
298
+ return this.compactRound("runGrowthRound", args);
299
+ }
300
+ publishPost(args) {
301
+ return this.single("publishPost", args, (a) => a.kind === "original" && a.draftPath === args.draftPath);
302
+ }
303
+ replyToPost(args) {
304
+ return this.single("replyToPost", args, (a) => a.kind === "reply" && a.postId === args.postId && a.text === args.text);
305
+ }
306
+ followOne(args) {
307
+ return this.single("followOne", args, (a) => a.kind === "follow" &&
308
+ a.handle?.toLowerCase() === args.handle.toLowerCase());
309
+ }
310
+ verifySubmission(args) {
311
+ return this.single("verifySubmission", args, (a) => a.id === args.actionId);
312
+ }
313
+ verifyPublishedPost(args) {
314
+ return this.single("verifyPublishedPost", args, (a) => a.kind === "original" && a.draftPath === args.draftPath);
315
+ }
316
+ async followBatch(args) {
317
+ const raw = await this.invoke("followBatch", args);
318
+ const output = {
319
+ status: raw.status ?? (raw.mayEnd ? "verified" : "needsDecision"),
320
+ taskId: args.taskId,
321
+ planned: raw.planned ?? args.handles.length,
322
+ attempted: raw.attempted ?? 0,
323
+ verified: raw.verifiedThisCall ?? 0,
324
+ unknown: raw.unknownInBatch ?? 0,
325
+ remaining: raw.remaining ?? args.handles.length,
326
+ mayEnd: raw.mayEnd === true,
327
+ };
328
+ if (raw.batchId)
329
+ output.batchId = raw.batchId;
330
+ if (raw.evidenceRef)
331
+ output.evidenceRef = raw.evidenceRef;
332
+ const d = diagnostic(raw.diagnostic);
333
+ if (d)
334
+ output.diagnostic = d;
335
+ const issues = decisions(raw.decision);
336
+ if (raw.reason)
337
+ issues.push({ reason: raw.reason, status: "needsDecision" });
338
+ if (raw.missing)
339
+ issues.push({ missing: raw.missing });
340
+ if (issues.length)
341
+ output.decision = issues;
342
+ return output;
343
+ }
344
+ async verifyFollow(args) {
345
+ const raw = await this.invoke("verifyFollow", {
346
+ ...args,
347
+ mode: args.mode ?? "receipt",
348
+ });
349
+ const out = readResult("verifyFollow", raw, "receipt");
350
+ out.handle = args.handle;
351
+ out.verified = raw.verified === true;
352
+ if (args.mode === "decision" && raw.observation)
353
+ out.person = readResult("readPerson", raw.observation, "decision").person;
354
+ return out;
355
+ }
356
+ }
357
+ export function createBusinessHarness(...args) {
358
+ return new BusinessHarness(...args);
308
359
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,15 @@
1
1
  export declare const plain: (label: any) => any;
2
2
  export declare const valueOf: (label: any) => any;
3
3
  export declare const missingMethods: (object: any, names: any) => any;
4
+ /** One instance owns one browser session and its concurrency boundary. */
5
+ export declare class SerializedBrowser {
6
+ #private;
7
+ collectCreator?: (args: unknown) => Promise<any>;
8
+ constructor(port: any);
9
+ private run;
10
+ observe(query: any): Promise<any>;
11
+ act(command: any): Promise<any>;
12
+ screenshot(): Promise<any>;
13
+ private collect;
14
+ }
4
15
  export declare function serialized(port: any): any;
@@ -1,29 +1,45 @@
1
1
  export const plain = (label) => label.replace(/^(?:按钮|link|文本输入区域|文本输入区|文本区域|文本栏) /, "");
2
2
  export const valueOf = (label) => label.match(/, Value: ([\s\S]*)$/)?.[1] ?? null;
3
3
  export const missingMethods = (object, names) => names.filter((name) => typeof object?.[name] !== "function");
4
- export function serialized(port) {
5
- let busy = false;
6
- const run = async (fn) => {
7
- if (busy)
4
+ /** One instance owns one browser session and its concurrency boundary. */
5
+ export class SerializedBrowser {
6
+ #busy = false;
7
+ #port;
8
+ collectCreator;
9
+ constructor(port) {
10
+ this.#port = port;
11
+ Object.assign(this, port);
12
+ this.observe = SerializedBrowser.prototype.observe.bind(this);
13
+ this.act = SerializedBrowser.prototype.act.bind(this);
14
+ this.screenshot = SerializedBrowser.prototype.screenshot.bind(this);
15
+ if (port.collectCreator)
16
+ this.collectCreator = this.collect.bind(this);
17
+ }
18
+ async run(fn) {
19
+ if (this.#busy)
8
20
  throw new Error("浏览器harness操作进行中,禁止并发");
9
- busy = true;
21
+ this.#busy = true;
10
22
  try {
11
23
  return await fn();
12
24
  }
13
25
  finally {
14
- busy = false;
26
+ this.#busy = false;
15
27
  }
16
- };
17
- return {
18
- ...port,
19
- observe: (query) => run(() => port.observe(query)),
20
- act: (command) => run(() => port.act(command)),
21
- screenshot: () => run(() => port.screenshot()),
22
- ...(port.collectCreator
23
- ? {
24
- collectCreator: (args) => run(() => port.collectCreator(args)),
25
- }
26
- : {}),
27
- };
28
+ }
29
+ observe(query) {
30
+ return this.run(() => this.#port.observe(query));
31
+ }
32
+ act(command) {
33
+ return this.run(() => this.#port.act(command));
34
+ }
35
+ screenshot() {
36
+ return this.run(() => this.#port.screenshot());
37
+ }
38
+ collect(args) {
39
+ return this.run(() => this.#port.collectCreator(args));
40
+ }
41
+ }
42
+ export function serialized(port) {
43
+ return new SerializedBrowser(port);
28
44
  }
29
45
  // AX indices never cross this port. Only semantic commands reach the platform layer.
@@ -1,4 +1,9 @@
1
1
  import type { DOMDependencies } from "./browser-dom-dependencies.js";
2
- export declare function createDOMCapabilities(dependencies: Pick<DOMDependencies, "tab" | "nativeSubmit">): {
2
+ export declare class DOMCapabilities {
3
+ #private;
4
+ constructor(dependencies: Pick<DOMDependencies, "tab" | "nativeSubmit">);
3
5
  capabilities(operation: any): any;
4
- };
6
+ private creatorCapabilities;
7
+ private collectionCapabilities;
8
+ }
9
+ export declare function createDOMCapabilities(...args: ConstructorParameters<typeof DOMCapabilities>): DOMCapabilities;
@@ -1,110 +1,131 @@
1
1
  import { missingMethods } from "./browser-common.js";
2
- export function createDOMCapabilities(dependencies) {
3
- const { tab, nativeSubmit } = dependencies;
4
- return {
5
- capabilities(operation) {
6
- const base = missingMethods(tab?.playwright, ["evaluate"]);
7
- if (operation === "readCreator") {
8
- base.push(...missingMethods(tab, [
9
- "url",
10
- "goto",
11
- "reload",
12
- "getAXState",
13
- "scroll",
2
+ export class DOMCapabilities {
3
+ #tab;
4
+ #nativeSubmit;
5
+ constructor(dependencies) {
6
+ this.capabilities = this.capabilities.bind(this);
7
+ const { tab, nativeSubmit } = dependencies;
8
+ this.#tab = tab;
9
+ this.#nativeSubmit = nativeSubmit;
10
+ }
11
+ capabilities(operation) {
12
+ const base = missingMethods(this.#tab?.playwright, ["evaluate"]);
13
+ if (operation === "readCreator") {
14
+ return this.creatorCapabilities(base, operation);
15
+ }
16
+ if (["readBookmarks", "searchSources", "readFeedback"].includes(operation)) {
17
+ return this.collectionCapabilities(base, operation);
18
+ }
19
+ if (operation !== "read")
20
+ base.push(...missingMethods(this.#tab?.playwright, ["getByRole"]), ...missingMethods(this.#tab, ["goto"]));
21
+ if (operation !== "read" &&
22
+ typeof this.#tab?.playwright?.getByRole === "function") {
23
+ base.push(...missingMethods(this.#tab.playwright.getByRole("button"), [
24
+ "count",
25
+ "click",
26
+ ]));
27
+ if (operation !== "submitFollow")
28
+ base.push(...missingMethods(this.#tab.playwright.getByRole("textbox"), [
29
+ "count",
30
+ "fill",
31
+ ]));
32
+ if (["submitPost", "submitReply"].includes(operation)) {
33
+ base.push(...missingMethods(this.#tab.playwright, [
34
+ "locator",
35
+ "waitForLoadState",
36
+ ]));
37
+ base.push(...missingMethods(this.#tab.playwright.getByRole("button"), [
38
+ "and",
39
+ "waitFor",
14
40
  ]));
15
- base.push(...missingMethods(tab.playwright, ["locator"]));
16
- if (typeof tab.playwright?.locator === "function") {
17
- const article = tab.playwright.locator("article");
18
- base.push(...missingMethods(article, ["first", "getByRole"]));
19
- if (typeof article.first === "function")
20
- base.push(...missingMethods(article.first(), ["waitFor"]));
21
- if (typeof article.getByRole === "function")
22
- base.push(...missingMethods(article.getByRole("button", { name: "显示更多", exact: true }), ["all"]));
23
- }
24
- return base;
25
- }
26
- if (["readBookmarks", "searchSources", "readFeedback"].includes(operation)) {
27
- base.push(...missingMethods(tab, ["goto"]));
28
- base.push(...missingMethods(tab?.playwright, ["getByRole", "waitForURL"]));
29
- if (typeof tab?.playwright?.getByRole === "function")
30
- base.push(...missingMethods(tab.playwright.getByRole("article"), [
31
- "first",
32
- "waitFor",
33
- ]));
34
- if (operation !== "readFeedback") {
35
- base.push(...missingMethods(tab?.playwright, [
36
- "getByRole",
37
- "getByText",
38
- "locator",
39
- "waitForURL",
40
- ]));
41
- if (typeof tab?.playwright?.getByRole === "function")
42
- base.push(...missingMethods(tab.playwright.getByRole("main"), [
43
- "count",
44
- "click",
45
- "first",
46
- "waitFor",
47
- ]));
48
- if (typeof tab?.playwright?.locator === "function")
49
- base.push(...missingMethods(tab.playwright.locator("a"), [
50
- "count",
51
- "filter",
52
- "press",
53
- ]));
54
- if (typeof tab?.playwright?.getByText === "function")
55
- base.push(...missingMethods(tab.playwright.getByText(""), ["waitFor"]));
56
- }
57
- return base;
58
41
  }
59
- if (operation !== "read")
60
- base.push(...missingMethods(tab?.playwright, ["getByRole"]), ...missingMethods(tab, ["goto"]));
61
- if (operation !== "read" &&
62
- typeof tab?.playwright?.getByRole === "function") {
63
- base.push(...missingMethods(tab.playwright.getByRole("button"), [
42
+ }
43
+ if (operation === "refreshPerson" || operation === "refreshPosts") {
44
+ base.push(...missingMethods(this.#tab, ["reload"]));
45
+ base.push(...missingMethods(this.#tab?.playwright, ["waitForLoadState"]));
46
+ if (typeof this.#tab?.playwright?.getByRole === "function")
47
+ base.push(...missingMethods(this.#tab.playwright.getByRole("button"), [
48
+ "waitFor",
49
+ ]));
50
+ }
51
+ if (operation === "openOwnPostMenu") {
52
+ base.push(...missingMethods(this.#tab?.playwright, ["locator"]));
53
+ if (typeof this.#tab?.playwright?.getByRole === "function")
54
+ base.push(...missingMethods(this.#tab.playwright.getByRole("article"), [
55
+ "filter",
56
+ "getByRole",
57
+ ]));
58
+ }
59
+ if (operation === "submitEditedPost") {
60
+ base.push(...missingMethods(this.#tab?.playwright, ["waitForLoadState"]));
61
+ if (typeof this.#tab?.playwright?.getByRole === "function")
62
+ base.push(...missingMethods(this.#tab.playwright.getByRole("button"), [
63
+ "press",
64
+ ]));
65
+ }
66
+ if (operation === "attachAssets")
67
+ base.push(...missingMethods(this.#tab?.playwright, [
68
+ "waitForEvent",
69
+ "getByLabel",
70
+ "getByPlaceholder",
71
+ ]));
72
+ if (this.#nativeSubmit && ["submitPost", "submitReply"].includes(operation))
73
+ base.push(...missingMethods(this.#tab, ["getAXState", "click"]));
74
+ return base;
75
+ }
76
+ creatorCapabilities(base, operation) {
77
+ base.push(...missingMethods(this.#tab, [
78
+ "url",
79
+ "goto",
80
+ "reload",
81
+ "getAXState",
82
+ "scroll",
83
+ ]));
84
+ base.push(...missingMethods(this.#tab.playwright, ["locator"]));
85
+ if (typeof this.#tab.playwright?.locator === "function") {
86
+ const article = this.#tab.playwright.locator("article");
87
+ base.push(...missingMethods(article, ["first", "getByRole"]));
88
+ if (typeof article.first === "function")
89
+ base.push(...missingMethods(article.first(), ["waitFor"]));
90
+ if (typeof article.getByRole === "function")
91
+ base.push(...missingMethods(article.getByRole("button", { name: "显示更多", exact: true }), ["all"]));
92
+ }
93
+ return base;
94
+ }
95
+ collectionCapabilities(base, operation) {
96
+ base.push(...missingMethods(this.#tab, ["goto"]));
97
+ base.push(...missingMethods(this.#tab?.playwright, ["getByRole", "waitForURL"]));
98
+ if (typeof this.#tab?.playwright?.getByRole === "function")
99
+ base.push(...missingMethods(this.#tab.playwright.getByRole("article"), [
100
+ "first",
101
+ "waitFor",
102
+ ]));
103
+ if (operation !== "readFeedback") {
104
+ base.push(...missingMethods(this.#tab?.playwright, [
105
+ "getByRole",
106
+ "getByText",
107
+ "locator",
108
+ "waitForURL",
109
+ ]));
110
+ if (typeof this.#tab?.playwright?.getByRole === "function")
111
+ base.push(...missingMethods(this.#tab.playwright.getByRole("main"), [
64
112
  "count",
65
113
  "click",
114
+ "first",
115
+ "waitFor",
66
116
  ]));
67
- if (operation !== "submitFollow")
68
- base.push(...missingMethods(tab.playwright.getByRole("textbox"), [
69
- "count",
70
- "fill",
71
- ]));
72
- if (["submitPost", "submitReply"].includes(operation)) {
73
- base.push(...missingMethods(tab.playwright, ["locator", "waitForLoadState"]));
74
- base.push(...missingMethods(tab.playwright.getByRole("button"), [
75
- "and",
76
- "waitFor",
77
- ]));
78
- }
79
- }
80
- if (operation === "refreshPerson" || operation === "refreshPosts") {
81
- base.push(...missingMethods(tab, ["reload"]));
82
- base.push(...missingMethods(tab?.playwright, ["waitForLoadState"]));
83
- if (typeof tab?.playwright?.getByRole === "function")
84
- base.push(...missingMethods(tab.playwright.getByRole("button"), ["waitFor"]));
85
- }
86
- if (operation === "openOwnPostMenu") {
87
- base.push(...missingMethods(tab?.playwright, ["locator"]));
88
- if (typeof tab?.playwright?.getByRole === "function")
89
- base.push(...missingMethods(tab.playwright.getByRole("article"), [
90
- "filter",
91
- "getByRole",
92
- ]));
93
- }
94
- if (operation === "submitEditedPost") {
95
- base.push(...missingMethods(tab?.playwright, ["waitForLoadState"]));
96
- if (typeof tab?.playwright?.getByRole === "function")
97
- base.push(...missingMethods(tab.playwright.getByRole("button"), ["press"]));
98
- }
99
- if (operation === "attachAssets")
100
- base.push(...missingMethods(tab?.playwright, [
101
- "waitForEvent",
102
- "getByLabel",
103
- "getByPlaceholder",
117
+ if (typeof this.#tab?.playwright?.locator === "function")
118
+ base.push(...missingMethods(this.#tab.playwright.locator("a"), [
119
+ "count",
120
+ "filter",
121
+ "press",
104
122
  ]));
105
- if (nativeSubmit && ["submitPost", "submitReply"].includes(operation))
106
- base.push(...missingMethods(tab, ["getAXState", "click"]));
107
- return base;
108
- },
109
- };
123
+ if (typeof this.#tab?.playwright?.getByText === "function")
124
+ base.push(...missingMethods(this.#tab.playwright.getByText(""), ["waitFor"]));
125
+ }
126
+ return base;
127
+ }
128
+ }
129
+ export function createDOMCapabilities(...args) {
130
+ return new DOMCapabilities(...args);
110
131
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,6 @@
1
1
  import type { DOMDependencies } from "./browser-dom-dependencies.js";
2
- export declare function createDOMEditing(dependencies: Pick<DOMDependencies, "session" | "unique" | "locator" | "tab" | "observe">): {
2
+ export declare class DOMEditing {
3
+ #private;
3
4
  dismissMenu: (command: any) => Promise<{
4
5
  completed: boolean;
5
6
  loc?: undefined;
@@ -145,4 +146,21 @@ export declare function createDOMEditing(dependencies: Pick<DOMDependencies, "se
145
146
  loc: any;
146
147
  submittedEditor: any;
147
148
  }>;
148
- };
149
+ constructor(dependencies: Pick<DOMDependencies, "session" | "unique" | "locator" | "tab" | "observe">);
150
+ private handleDismissMenu;
151
+ private handleOpenControl;
152
+ private handleOpenOwnPostMenu;
153
+ private handleSubmitEditedPost;
154
+ private handleExpandPost;
155
+ private handleNextPosts;
156
+ private handleClearPreparedText;
157
+ private handleClosePreparedReply;
158
+ private handleClosePreparedMedia;
159
+ private handleRemovePreparedMedia;
160
+ private handleAttachAssets;
161
+ private handleFollow;
162
+ private handleOpenReply;
163
+ private handleFillComposer;
164
+ private handleSubmitPost;
165
+ }
166
+ export declare function createDOMEditing(...args: ConstructorParameters<typeof DOMEditing>): DOMEditing;