@nextclaw/x-harness 0.2.54 → 0.2.55

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/SOURCE.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Corresponding source
2
2
 
3
- Version 0.2.54, commit a9b2bb0d7399463a8dc259e433e3a2bd31dc9bc7.
3
+ Version 0.2.55, commit 7fc4a6a0e9bcea24ea2ac8d739572dc15afad136.
4
4
 
5
- Complete source, build scripts and dependencies: https://github.com/Peiiii/x-harness/tree/a9b2bb0d7399463a8dc259e433e3a2bd31dc9bc7
5
+ Complete source, build scripts and dependencies: https://github.com/Peiiii/x-harness/tree/7fc4a6a0e9bcea24ea2ac8d739572dc15afad136
6
6
 
7
7
  Clone this revision, run npm ci, npm run bootstrap and npm run release:build.
8
8
 
@@ -196,7 +196,7 @@ export class DOMEditing {
196
196
  throw new Error("翻页须有已观察原帖链接");
197
197
  const anchor = await this.#unique(this.#tab.playwright
198
198
  .locator(`a[href=${JSON.stringify(primary)}]`)
199
- .filter({ visible: true }));
199
+ .filter({ has: this.#tab.playwright.locator("time") }));
200
200
  this.#session.current = null;
201
201
  await anchor.press("PageDown");
202
202
  return { completed: true };
@@ -3,6 +3,5 @@ export declare class DOMSubmission {
3
3
  #private;
4
4
  constructor(dependencies: Pick<DOMDependencies, "submitAX" | "session" | "tab" | "observe" | "unique" | "locator">);
5
5
  finishDOMAction(command: any, prepared: any, query: any, result: any): Promise<void>;
6
- private waitSubmittedEditor;
7
6
  }
8
7
  export declare function createDOMSubmission(...args: ConstructorParameters<typeof DOMSubmission>): (command: any, prepared: any, query: any, result: any) => Promise<void>;
@@ -1,4 +1,4 @@
1
- import { xURL, sameHandle, sameText } from "./platform-rules.js";
1
+ import { xURL } from "./platform-rules.js";
2
2
  import { valueOf } from "./browser-common.js";
3
3
  export class DOMSubmission {
4
4
  #submitAX;
@@ -29,7 +29,6 @@ export class DOMSubmission {
29
29
  : null;
30
30
  let nativeSubmitIndex;
31
31
  if (this.#submitAX &&
32
- command.activation !== "keyboard" &&
33
32
  ["submitPost", "submitReply"].includes(command.operation)) {
34
33
  const native = await this.#submitAX.observe({ mode: "composer" });
35
34
  const editors = native.evidence?.filter((e) => /^(?:文本输入区(?:域)?|文本区域|文本栏) /.test(e.label)) ?? [];
@@ -89,7 +88,7 @@ export class DOMSubmission {
89
88
  // Inline replies keep the editor mounted. Wait for this submitted text to clear before
90
89
  // receipt navigation/reload can interrupt the actual submission request.
91
90
  if (submittedEditor)
92
- await this.waitSubmittedEditor(submittedEditor, result);
91
+ await submittedEditor.waitFor({ state: "hidden", timeoutMs: 10000 });
93
92
  if (["submitPost", "submitReply"].includes(command.operation)) {
94
93
  try {
95
94
  await this.#tab.playwright.waitForLoadState({
@@ -105,36 +104,6 @@ export class DOMSubmission {
105
104
  }
106
105
  }
107
106
  }
108
- async waitSubmittedEditor(editor, submitted) {
109
- const deadline = Date.now() + 10000;
110
- for (let attempt = 0; attempt < 4; attempt++) {
111
- const remaining = deadline - Date.now();
112
- if (remaining <= 0)
113
- throw Error("submitted-editor-clear-timeout");
114
- try {
115
- await editor.waitFor({ state: "hidden", timeoutMs: remaining });
116
- return;
117
- }
118
- catch (error) {
119
- if (!/timed out|timeout|deadline exceeded/i.test(error.message) ||
120
- attempt === 3 ||
121
- Date.now() >= deadline)
122
- throw error;
123
- // Resume only the wait, never the submission or a navigation that could interrupt it.
124
- const current = await this.#observe({ view: "composer" });
125
- if (current.alerts?.length ||
126
- !current.accountHandle ||
127
- !submitted.accountHandle ||
128
- !sameHandle(current.accountHandle, submitted.accountHandle) ||
129
- xURL(current.page).href !== xURL(submitted.page).href ||
130
- (typeof current.editorText === "string" &&
131
- current.editorText.trim() &&
132
- (!sameText(current.editorText, submitted.editorText) ||
133
- current.replyToId !== submitted.replyToId)))
134
- throw error;
135
- }
136
- }
137
- }
138
107
  }
139
108
  export function createDOMSubmission(...args) {
140
109
  return new DOMSubmission(...args).finishDOMAction;
@@ -83,7 +83,7 @@ export class IndependentPublishing {
83
83
  const baseline = await this.#platform.findSubmission({
84
84
  ...action,
85
85
  intentAt: this.#stamp(),
86
- });
86
+ }, { phase: "baseline" });
87
87
  if (baseline.needsStateCheck || baseline.alerts?.length)
88
88
  throw new Error("publication-baseline-unconfirmed");
89
89
  token = `${action.id}:${this.#stamp()}:${Math.random()}`;
@@ -31,7 +31,9 @@ export interface PlatformDependencies {
31
31
  readFeedback: ({ targets, replyLimit }?: any) => Promise<any>;
32
32
  readPerson: (target: any) => Promise<any>;
33
33
  readPost: (target: any) => Promise<any>;
34
- findSubmission: (action: any) => Promise<any>;
34
+ findSubmission: (action: any, context?: {
35
+ phase?: "baseline";
36
+ }) => Promise<any>;
35
37
  submitFollow: (action: any) => Promise<any>;
36
38
  submitPost: (action: any) => Promise<any>;
37
39
  submitReply: (action: any) => Promise<any>;
@@ -2,7 +2,9 @@ import type { PlatformDependencies } from "./platform-dependencies.js";
2
2
  export declare class PlatformWriting {
3
3
  #private;
4
4
  compose: (action: any) => Promise<any>;
5
- findSubmission: (action: any) => Promise<any>;
5
+ findSubmission: (action: any, context?: {
6
+ phase?: "baseline";
7
+ }) => Promise<any>;
6
8
  submitFollow: (action: any) => Promise<any>;
7
9
  submitPost: (action: any) => Promise<any>;
8
10
  submitReply: (action: any) => Promise<any>;
@@ -58,7 +58,7 @@ export class PlatformWriting {
58
58
  ...(action.activation ? { activation: action.activation } : {}),
59
59
  });
60
60
  }
61
- async handleFindSubmission(action) {
61
+ async handleFindSubmission(action, context = {}) {
62
62
  if (action.kind === "follow") {
63
63
  let value = await this.#followStage(action, "verify-read", () => this.#readPerson(action));
64
64
  const verificationAlerts = [...(value.alerts ?? [])];
@@ -117,7 +117,8 @@ export class PlatformWriting {
117
117
  ? { url: action.url, evidenceRef: action.evidenceRef }
118
118
  : { url: action.accountURL, evidenceRef: action.accountEvidenceRef };
119
119
  let value = await this.#open(receiptTarget, { view: "posts", limit: 5 });
120
- if (!(action.kind === "original" && observedReceipt) &&
120
+ if (context.phase !== "baseline" &&
121
+ !(action.kind === "original" && observedReceipt) &&
121
122
  !value.needsStateCheck &&
122
123
  !(this.#browser.capabilities?.("refreshPosts") ?? ["refreshPosts"]).length) {
123
124
  await this.#browser.act({
@@ -11,7 +11,9 @@ export declare class XPlatform {
11
11
  readFeedback: ({ targets, replyLimit }?: any) => Promise<any>;
12
12
  readPerson: (target: any) => Promise<any>;
13
13
  readPost: (target: any) => Promise<any>;
14
- findSubmission: (action: any) => Promise<any>;
14
+ findSubmission: (action: any, context?: {
15
+ phase?: "baseline";
16
+ }) => Promise<any>;
15
17
  submitFollow: (action: any) => Promise<any>;
16
18
  submitPost: (action: any) => Promise<any>;
17
19
  submitReply: (action: any) => Promise<any>;
@@ -23,7 +23,7 @@ export function readNavigation({ targetLabel, bookmarkNavigation = false, } = {}
23
23
  ...new Set([
24
24
  ...Array.from(document.querySelectorAll("nav a[href],nav button")).filter((el) => !el.closest("main")),
25
25
  ...Array.from(primary?.querySelectorAll('a[href],button,[role="button"],[role="tab"]') ?? []),
26
- ...Array.from(document.querySelectorAll('[role="menu"] a[href], [role="menu"] button, [data-testid="Dropdown"] a[href], [data-testid="Dropdown"] button')),
26
+ ...Array.from(document.querySelectorAll('[role="menu"] a[href], [role="menu"] button, [data-testid="Dropdown"] a[href], [data-testid="Dropdown"] button, [data-testid="Dropdown"] [role="menuitemradio"]')),
27
27
  ]),
28
28
  ].filter((el) => visible(el) &&
29
29
  !el.closest("article") &&
@@ -445,7 +445,7 @@ export const readXObservation = (query) => {
445
445
  ...new Set([
446
446
  ...Array.from(document.querySelectorAll("nav a[href],nav button")).filter((el) => !el.closest("main")),
447
447
  ...Array.from(primary?.querySelectorAll('a[href],button,[role="button"],[role="tab"]') ?? []),
448
- ...Array.from(document.querySelectorAll('[role="menu"] a[href], [role="menu"] button, [data-testid="Dropdown"] a[href], [data-testid="Dropdown"] button')),
448
+ ...Array.from(document.querySelectorAll('[role="menu"] a[href], [role="menu"] button, [data-testid="Dropdown"] a[href], [data-testid="Dropdown"] button, [data-testid="Dropdown"] [role="menuitemradio"]')),
449
449
  ]),
450
450
  ].filter((el) => visible(el) &&
451
451
  !el.closest("article") &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/x-harness",
3
- "version": "0.2.54",
3
+ "version": "0.2.55",
4
4
  "type": "module",
5
5
  "description": "Typed X task harness with compact business results and explicit diagnostics.",
6
6
  "main": "./dist/index.js",
@@ -42,5 +42,5 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "gitHead": "a9b2bb0d7399463a8dc259e433e3a2bd31dc9bc7"
45
+ "gitHead": "7fc4a6a0e9bcea24ea2ac8d739572dc15afad136"
46
46
  }