@nextclaw/x-harness 0.1.0 → 0.2.0

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 (113) hide show
  1. package/LICENSE +231 -6
  2. package/README.md +17 -3
  3. package/SOURCE.md +9 -0
  4. package/cli/main.js +232 -188
  5. package/dist/api.d.ts +56 -2
  6. package/dist/api.js +178 -75
  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 +9 -0
  11. package/dist/browser-dom-capabilities.js +131 -0
  12. package/dist/browser-dom-dependencies.d.ts +16 -0
  13. package/dist/browser-dom-dependencies.js +1 -0
  14. package/dist/browser-dom-editing.d.ts +166 -0
  15. package/dist/browser-dom-editing.js +418 -0
  16. package/dist/browser-dom-navigation.d.ts +18 -0
  17. package/dist/browser-dom-navigation.js +181 -0
  18. package/dist/browser-dom-network.d.ts +1 -0
  19. package/dist/browser-dom-network.js +128 -0
  20. package/dist/browser-dom-submission.d.ts +7 -0
  21. package/dist/browser-dom-submission.js +101 -0
  22. package/dist/browser-dom.d.ts +14 -2
  23. package/dist/browser-dom.js +120 -824
  24. package/dist/browser-native.d.ts +14 -1
  25. package/dist/browser-native.js +180 -143
  26. package/dist/browser.js +6 -2
  27. package/dist/creator-native.d.ts +3 -0
  28. package/dist/creator-native.js +113 -0
  29. package/dist/creator.js +1 -1
  30. package/dist/diagnostics.d.ts +11 -0
  31. package/dist/diagnostics.js +10 -0
  32. package/dist/growth-batch.d.ts +8 -0
  33. package/dist/growth-batch.js +190 -0
  34. package/dist/growth-constants.d.ts +5 -0
  35. package/dist/growth-constants.js +13 -0
  36. package/dist/growth-dependencies.d.ts +33 -0
  37. package/dist/growth-dependencies.js +1 -0
  38. package/dist/growth-execution.d.ts +17 -0
  39. package/dist/growth-execution.js +346 -0
  40. package/dist/growth-parallel.d.ts +8 -0
  41. package/dist/growth-parallel.js +332 -0
  42. package/dist/growth-plan.d.ts +9 -0
  43. package/dist/growth-plan.js +229 -0
  44. package/dist/growth-policy.d.ts +18 -0
  45. package/dist/growth-policy.js +208 -0
  46. package/dist/growth-publishing.d.ts +10 -0
  47. package/dist/growth-publishing.js +266 -0
  48. package/dist/growth-reading.d.ts +8 -0
  49. package/dist/growth-reading.js +157 -0
  50. package/dist/growth-recovery.d.ts +9 -0
  51. package/dist/growth-recovery.js +187 -0
  52. package/dist/growth-state.d.ts +16 -0
  53. package/dist/growth-state.js +220 -0
  54. package/dist/growth-tasks.d.ts +20 -0
  55. package/dist/growth-tasks.js +164 -0
  56. package/dist/growth.d.ts +26 -1
  57. package/dist/growth.js +211 -1908
  58. package/dist/platform-capabilities.d.ts +8 -0
  59. package/dist/platform-capabilities.js +29 -0
  60. package/dist/platform-collections.d.ts +14 -0
  61. package/dist/platform-collections.js +250 -0
  62. package/dist/platform-dependencies.d.ts +43 -0
  63. package/dist/platform-dependencies.js +1 -0
  64. package/dist/platform-diagnostics.d.ts +14 -0
  65. package/dist/platform-diagnostics.js +63 -0
  66. package/dist/platform-observation.d.ts +16 -0
  67. package/dist/platform-observation.js +96 -0
  68. package/dist/platform-rules.d.ts +17 -0
  69. package/dist/platform-rules.js +41 -0
  70. package/dist/platform-targets.d.ts +14 -0
  71. package/dist/platform-targets.js +154 -0
  72. package/dist/platform-writing.d.ts +16 -0
  73. package/dist/platform-writing.js +202 -0
  74. package/dist/platform.d.ts +23 -2
  75. package/dist/platform.js +125 -678
  76. package/dist/readers-actions.d.ts +2 -0
  77. package/dist/readers-actions.js +66 -0
  78. package/dist/readers-ax-host.d.ts +12 -0
  79. package/dist/readers-ax-host.js +134 -0
  80. package/dist/readers-ax-parser.d.ts +1 -0
  81. package/dist/readers-ax-parser.js +69 -0
  82. package/dist/readers-ax-program.d.ts +1 -0
  83. package/dist/readers-ax-program.js +5 -0
  84. package/dist/readers-ax-tree.d.ts +19 -0
  85. package/dist/readers-ax-tree.js +111 -0
  86. package/dist/readers-ax-views.d.ts +87 -0
  87. package/dist/readers-ax-views.js +247 -0
  88. package/dist/readers-cli.d.ts +6 -0
  89. package/dist/readers-cli.js +79 -0
  90. package/dist/readers-composer.d.ts +2 -0
  91. package/dist/readers-composer.js +131 -0
  92. package/dist/readers-navigation.d.ts +2 -0
  93. package/dist/readers-navigation.js +66 -0
  94. package/dist/readers-posts.d.ts +2 -0
  95. package/dist/readers-posts.js +141 -0
  96. package/dist/readers-profile.d.ts +3 -0
  97. package/dist/readers-profile.js +157 -0
  98. package/dist/readers.d.ts +9 -20
  99. package/dist/readers.js +9 -1045
  100. package/dist/results.js +1 -1
  101. package/dist/round-state.js +20 -3
  102. package/dist/store.d.ts +22 -4
  103. package/dist/store.js +173 -151
  104. package/dist/types.d.ts +10 -0
  105. package/dist/types.js +1 -0
  106. package/generated/observation.mjs +3 -2
  107. package/package.json +23 -9
  108. package/skill/SKILL.md +17 -36
  109. package/skill/references/api.md +7 -34
  110. package/skill/references/reads.md +23 -0
  111. package/skill/references/recovery.md +25 -0
  112. package/skill/references/setup.md +23 -0
  113. package/skill/references/writes.md +51 -0
package/dist/api.js CHANGED
@@ -1,19 +1,80 @@
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
- return await core[operation](args);
31
+ const raw = await this.#core[operation](args);
32
+ // Legacy core decisions can contain a human error without a diagnostic proof.
33
+ // Expose a bounded recovery route; consumers never need implementation source.
34
+ const errors = [
35
+ raw.reason,
36
+ ...(raw.decision ?? []).flatMap((d) => [
37
+ d.reason,
38
+ d.error,
39
+ ]),
40
+ ].filter((reason) => typeof reason === "string" && stableReason(reason) !== reason);
41
+ if (errors.length) {
42
+ const evidenceRef = await this.#store.recordProof({
43
+ operation,
44
+ error: errors[0],
45
+ ...(errors.length > 1 ? { errors } : {}),
46
+ });
47
+ return {
48
+ ...raw,
49
+ ...(raw.reason ? { reason: stableReason(raw.reason) } : {}),
50
+ evidenceRef,
51
+ ...(raw.decision
52
+ ? {
53
+ decision: raw.decision.map((d) => ({
54
+ ...d,
55
+ reason: stableReason(d.reason),
56
+ })),
57
+ }
58
+ : {}),
59
+ diagnostic: {
60
+ operation,
61
+ category: "boundary",
62
+ code: "harness-boundary-error",
63
+ next: "inspect-local-proof",
64
+ evidenceRef,
65
+ },
66
+ };
67
+ }
68
+ return raw;
11
69
  }
12
70
  catch (error) {
13
71
  const message = error instanceof Error ? error.message : String(error);
14
72
  let evidenceRef;
15
73
  try {
16
- evidenceRef = await store.recordProof({ operation, error: message });
74
+ evidenceRef = await this.#store.recordProof({
75
+ operation,
76
+ error: message,
77
+ });
17
78
  }
18
79
  catch {
19
80
  /* Evidence failure is explicit below. */
@@ -29,10 +90,19 @@ export function createBusinessHarness(dependencies) {
29
90
  ...(evidenceRef
30
91
  ? { evidenceRef }
31
92
  : { missing: ["local-proof-unavailable"] }),
93
+ diagnostic: {
94
+ operation,
95
+ category: "boundary",
96
+ code: evidenceRef
97
+ ? "harness-boundary-error"
98
+ : "evidence-store-unavailable",
99
+ next: evidenceRef ? "inspect-local-proof" : "restore-proof-store",
100
+ ...(evidenceRef ? { evidenceRef } : {}),
101
+ },
32
102
  };
33
103
  }
34
104
  }
35
- async function read(operation, args = {}, mode = "receipt") {
105
+ async read(operation, args = {}, mode = "receipt") {
36
106
  if (!["receipt", "decision", "delta"].includes(mode))
37
107
  return {
38
108
  status: "needsDecision",
@@ -40,7 +110,7 @@ export function createBusinessHarness(dependencies) {
40
110
  reason: "read-mode-invalid",
41
111
  };
42
112
  // Always collect fresh evidence once. Projection, not a second browser call, chooses output.
43
- const raw = await invoke(operation, { ...args, mode: "decision" });
113
+ const raw = await this.invoke(operation, { ...args, mode: "decision" });
44
114
  const output = readResult(operation, raw, mode);
45
115
  if (mode === "receipt")
46
116
  return output;
@@ -55,11 +125,11 @@ export function createBusinessHarness(dependencies) {
55
125
  continue;
56
126
  }
57
127
  const key = JSON.stringify([operation, id]), value = JSON.stringify(entry);
58
- if (readCache.get(key) === value)
128
+ if (this.#readCache.get(key) === value)
59
129
  unchangedIds.push(id);
60
130
  else
61
131
  changed.push(entry);
62
- readCache.set(key, value);
132
+ this.#readCache.set(key, value);
63
133
  }
64
134
  // Creator metadata changes independently from the post collection.
65
135
  if (operation === "readCreator") {
@@ -68,9 +138,9 @@ export function createBusinessHarness(dependencies) {
68
138
  continue;
69
139
  const key = JSON.stringify([operation, name, args.handle]);
70
140
  const value = JSON.stringify(output[name], (k, v) => k === "observedAt" ? undefined : v);
71
- if (mode === "delta" && readCache.get(key) === value)
141
+ if (mode === "delta" && this.#readCache.get(key) === value)
72
142
  delete output[name];
73
- readCache.set(key, value);
143
+ this.#readCache.set(key, value);
74
144
  }
75
145
  }
76
146
  // A decision has delivered complete evidence and seeds the next delta.
@@ -87,8 +157,8 @@ export function createBusinessHarness(dependencies) {
87
157
  output.unchangedIds = unchangedIds;
88
158
  return output;
89
159
  }
90
- async function compactRound(operation, args) {
91
- const raw = await invoke(operation, args);
160
+ async compactRound(operation, args) {
161
+ const raw = await this.invoke(operation, args);
92
162
  const out = {
93
163
  status: raw.status,
94
164
  taskId: args.taskId,
@@ -112,6 +182,9 @@ export function createBusinessHarness(dependencies) {
112
182
  out.decision = issues;
113
183
  if (raw.evidenceRef)
114
184
  out.evidenceRef = raw.evidenceRef;
185
+ const d = diagnostic(raw.diagnostic);
186
+ if (d)
187
+ out.diagnostic = d;
115
188
  if (Array.isArray(raw.settlementErrors))
116
189
  out.settlementErrors = raw.settlementErrors
117
190
  .map(stableReason)
@@ -132,11 +205,11 @@ export function createBusinessHarness(dependencies) {
132
205
  };
133
206
  return out;
134
207
  }
135
- async function single(operation, args, selector) {
136
- const raw = await invoke(operation, args);
208
+ async single(operation, args, selector) {
209
+ const raw = await this.invoke(operation, args);
137
210
  let snapshot;
138
211
  try {
139
- snapshot = await store.load();
212
+ snapshot = await this.#store.load();
140
213
  }
141
214
  catch {
142
215
  return {
@@ -197,60 +270,90 @@ export function createBusinessHarness(dependencies) {
197
270
  out.diagnostic = d;
198
271
  return out;
199
272
  }
200
- return {
201
- readCreator: (args) => read("readCreator", args, args.mode),
202
- readBookmarks: (args) => read("readBookmarks", args, args.mode),
203
- searchSources: (args) => read("searchSources", args, args.mode),
204
- readPost: ({ target, mode }) => read("readPost", target, mode),
205
- readPerson: ({ target, mode }) => read("readPerson", target, mode),
206
- readFeedback: (args) => read("readFeedback", args, args.mode),
207
- inspectAccount: (args = {}) => read("inspectAccount", args, args.mode),
208
- inspectRound: (args) => compactRound("inspectRound", args),
209
- runGrowthRound: (args) => compactRound("runGrowthRound", args),
210
- publishPost: (args) => single("publishPost", args, (a) => a.kind === "original" && a.draftPath === args.draftPath),
211
- replyToPost: (args) => single("replyToPost", args, (a) => a.kind === "reply" &&
212
- a.postId === args.postId &&
213
- a.text === args.text),
214
- followOne: (args) => single("followOne", args, (a) => a.kind === "follow" &&
215
- a.handle?.toLowerCase() === args.handle.toLowerCase()),
216
- verifySubmission: (args) => single("verifySubmission", args, (a) => a.id === args.actionId),
217
- verifyPublishedPost: (args) => single("verifyPublishedPost", args, (a) => a.kind === "original" && a.draftPath === args.draftPath),
218
- followBatch: async (args) => {
219
- const raw = await invoke("followBatch", args);
220
- const output = {
221
- status: raw.status ?? (raw.mayEnd ? "verified" : "needsDecision"),
222
- taskId: args.taskId,
223
- planned: raw.planned ?? args.handles.length,
224
- attempted: raw.attempted ?? 0,
225
- verified: raw.verifiedThisCall ?? 0,
226
- unknown: raw.unknownInBatch ?? 0,
227
- remaining: raw.remaining ?? args.handles.length,
228
- mayEnd: raw.mayEnd === true,
229
- };
230
- if (raw.batchId)
231
- output.batchId = raw.batchId;
232
- if (raw.evidenceRef)
233
- output.evidenceRef = raw.evidenceRef;
234
- const issues = decisions(raw.decision);
235
- if (raw.reason)
236
- issues.push({ reason: raw.reason, status: "needsDecision" });
237
- if (raw.missing)
238
- issues.push({ missing: raw.missing });
239
- if (issues.length)
240
- output.decision = issues;
241
- return output;
242
- },
243
- verifyFollow: async (args) => {
244
- const raw = await invoke("verifyFollow", {
245
- ...args,
246
- mode: args.mode ?? "receipt",
247
- });
248
- const out = readResult("verifyFollow", raw, "receipt");
249
- out.handle = args.handle;
250
- out.verified = raw.verified === true;
251
- if (args.mode === "decision" && raw.observation)
252
- out.person = readResult("readPerson", raw.observation, "decision").person;
253
- return out;
254
- },
255
- };
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);
256
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.
@@ -0,0 +1,9 @@
1
+ import type { DOMDependencies } from "./browser-dom-dependencies.js";
2
+ export declare class DOMCapabilities {
3
+ #private;
4
+ constructor(dependencies: Pick<DOMDependencies, "tab" | "nativeSubmit">);
5
+ capabilities(operation: any): any;
6
+ private creatorCapabilities;
7
+ private collectionCapabilities;
8
+ }
9
+ export declare function createDOMCapabilities(...args: ConstructorParameters<typeof DOMCapabilities>): DOMCapabilities;
@@ -0,0 +1,131 @@
1
+ import { missingMethods } from "./browser-common.js";
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",
40
+ ]));
41
+ }
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"), [
112
+ "count",
113
+ "click",
114
+ "first",
115
+ "waitFor",
116
+ ]));
117
+ if (typeof this.#tab?.playwright?.locator === "function")
118
+ base.push(...missingMethods(this.#tab.playwright.locator("a"), [
119
+ "count",
120
+ "filter",
121
+ "press",
122
+ ]));
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);
131
+ }
@@ -0,0 +1,16 @@
1
+ export interface DOMSession {
2
+ current?: any;
3
+ replyBinding?: any;
4
+ refreshNotice?: any;
5
+ editBinding?: any;
6
+ }
7
+ export interface DOMDependencies {
8
+ tab: any;
9
+ nativeSubmit: boolean;
10
+ readDOM: any;
11
+ session: DOMSession;
12
+ submitAX: any;
13
+ observe: (query: any) => Promise<any>;
14
+ locator: (role: any, name?: any) => any;
15
+ unique: (loc: any) => Promise<any>;
16
+ }
@@ -0,0 +1 @@
1
+ export {};