@nextclaw/x-harness 0.2.47 → 0.2.49

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.47, commit b993ce6df34c50bdff2f4010b5935ca532f12f7a.
3
+ Version 0.2.49, commit d4a3b2e37cebcd8bb86fd558faad4e3b2022e5ab.
4
4
 
5
- Complete source, build scripts and dependencies: https://github.com/Peiiii/x-harness/tree/b993ce6df34c50bdff2f4010b5935ca532f12f7a
5
+ Complete source, build scripts and dependencies: https://github.com/Peiiii/x-harness/tree/d4a3b2e37cebcd8bb86fd558faad4e3b2022e5ab
6
6
 
7
7
  Clone this revision, run npm ci, npm run bootstrap and npm run release:build.
8
8
 
@@ -146,6 +146,7 @@ export class DOMCapabilities {
146
146
  if (typeof this.#tab?.playwright?.getByRole === "function")
147
147
  base.push(...missingMethods(this.#tab.playwright.getByRole("article"), [
148
148
  "first",
149
+ "filter",
149
150
  "waitFor",
150
151
  ]));
151
152
  if (operation === "readBookmarks" &&
@@ -198,7 +198,7 @@ export class DOMEditing {
198
198
  .locator(`a[href=${JSON.stringify(primary)}]`)
199
199
  .filter({ visible: true }));
200
200
  this.#session.current = null;
201
- await anchor.press("PageDown");
201
+ await anchor.press("End");
202
202
  return { completed: true };
203
203
  return { completed: false, loc, submittedEditor };
204
204
  }
@@ -100,6 +100,20 @@ export class DOMNavigation {
100
100
  .waitFor({ state: "visible", timeoutMs: 5000 });
101
101
  return;
102
102
  }
103
+ if (command.excludeIds) {
104
+ if (!Array.isArray(command.excludeIds) ||
105
+ command.excludeIds.some((id) => !/^\d+$/.test(id)))
106
+ throw Error("source-pagination-wait-ids-invalid");
107
+ let articles = this.#tab.playwright.getByRole("article");
108
+ if (command.excludeIds.length)
109
+ articles = articles.filter({
110
+ hasNot: this.#tab.playwright.locator(command.excludeIds
111
+ .map((id) => `a[href$="/status/${id}"]`)
112
+ .join(",")),
113
+ });
114
+ await articles.first().waitFor({ state: "visible", timeoutMs: 5000 });
115
+ return;
116
+ }
103
117
  const offset = command.offset ?? 0;
104
118
  if (!Number.isInteger(offset) || offset < 0)
105
119
  throw Error("帖子等待窗口须为非负整数offset");
@@ -118,6 +118,26 @@ export class PlatformCollections {
118
118
  offset += 5;
119
119
  else {
120
120
  await this.#browser.act({ operation: "nextPosts" });
121
+ const scrolled = await this.#ready({ view: "posts", limit: 5 });
122
+ if (scrolled.needsStateCheck || scrolled.alerts?.length)
123
+ return {
124
+ ...scrolled,
125
+ sources,
126
+ complete: false,
127
+ missing: ["source-page-unconfirmed"],
128
+ };
129
+ // Scroll and lazy loading settle asynchronously. Existing cards are
130
+ // already visible, so waiting for the first article proves nothing.
131
+ try {
132
+ await this.#browser.act({
133
+ operation: "waitForPosts",
134
+ excludeIds: [...seen],
135
+ });
136
+ }
137
+ catch (error) {
138
+ if (!/timed out|timeout/i.test(error.message))
139
+ throw error;
140
+ }
121
141
  const advanced = await this.#ready({ view: "posts", limit: 5 });
122
142
  // Retained DOM prefixes include a partial final window too; skip
123
143
  // exactly the consumed cards, while virtualized replacements restart.
@@ -62,9 +62,9 @@ export class PlatformObservation {
62
62
  const waitingForOffset = query.view === "posts" &&
63
63
  Number.isInteger(query.offset) &&
64
64
  query.offset > 0 &&
65
- value.renderedArticles > 0 &&
66
65
  !value.posts?.length;
67
- if ((value.needsStateCheck || waitingForOffset) &&
66
+ const waitingForList = query.view === "posts" && !query.targetId && !value.posts?.length;
67
+ if ((value.needsStateCheck || waitingForOffset || waitingForList) &&
68
68
  !value.alerts?.length &&
69
69
  query.view === "posts") {
70
70
  try {
@@ -78,6 +78,8 @@ export class PlatformObservation {
78
78
  throw error;
79
79
  }
80
80
  value = await this.handleObserved(query);
81
+ if (waitingForList && !query.offset && !value.posts?.length)
82
+ value = { ...value, needsStateCheck: true };
81
83
  }
82
84
  return value;
83
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/x-harness",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
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": "b993ce6df34c50bdff2f4010b5935ca532f12f7a"
45
+ "gitHead": "d4a3b2e37cebcd8bb86fd558faad4e3b2022e5ab"
46
46
  }
@@ -4,8 +4,8 @@
4
4
  | --- | --- | --- |
5
5
  | readIncomingReplies | none | processedIds, limit (5), maxPages (3), mode |
6
6
  | readCreator | handle | target (10;1–50), maxScrolls, navigate, expand, mode |
7
- | readBookmarks | folder (observed name), or discoverOnly:true | processedIds, limit, maxPages, mode |
8
- | searchSources | query | processedIds, limit, maxPages, mode |
7
+ | readBookmarks | folder (observed name), or discoverOnly:true | processedIds, limit (1–5), maxPages (1–10), mode |
8
+ | searchSources | query | processedIds, limit (1–5), maxPages (1–10), mode |
9
9
  | readPost | target: {postId,url,evidenceRef} | includeContext, resolveQuote, mode |
10
10
  | readPerson | target: {handle,url,evidenceRef} | mode |
11
11
  | readPeople | target: {url,evidenceRef} | offset, limit (1–5), advance, mode |