@xingwangzhe/stalux 1.13.0 → 1.15.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "description": "A powerful, modern Astro blog theme — use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
@@ -98,6 +98,7 @@
98
98
  },
99
99
  "devDependencies": {
100
100
  "@types/node": "^26.1.2",
101
+ "astro": "^7.2.0",
101
102
  "knip": "^6.31.0",
102
103
  "license-checker-rseidelsohn": "5.0.1",
103
104
  "oxfmt": "^0.62.0",
@@ -105,6 +106,6 @@
105
106
  "typescript": "^7.0.2"
106
107
  },
107
108
  "peerDependencies": {
108
- "astro": "^7.1.6"
109
+ "astro": "7.2.0"
109
110
  }
110
111
  }
@@ -35,8 +35,16 @@ export async function getStaticPaths() {
35
35
  // sorted 按日期降序:sorted[i-1] 比当前新(next),sorted[i+1] 比当前旧(prev)
36
36
  const nextPost = i > 0 ? sorted[i - 1] : undefined;
37
37
  const prevPost = i < sorted.length - 1 ? sorted[i + 1] : undefined;
38
+ // 增量构建 cacheKey:含自身与 prev/next 的更新时间,
39
+ // 任一邻居变化(文章新增/编辑导致前后链接变化)时本页也会失效重渲染
40
+ const cacheKey = [
41
+ post.data.updated ?? post.data.date,
42
+ prevPost ? (prevPost.data.updated ?? prevPost.data.date) : "",
43
+ nextPost ? (nextPost.data.updated ?? nextPost.data.date) : "",
44
+ ].join("|");
38
45
  return {
39
46
  params: { post: post.data.abbrlink },
47
+ cacheKey,
40
48
  props: {
41
49
  post,
42
50
  prev: prevPost
@@ -78,6 +78,7 @@ export const getStaticPaths = (async () => {
78
78
  const posts = await getCollection("posts", ({ data }) => !data.draft);
79
79
  return posts.map((post) => ({
80
80
  params: { post: String(post.data.abbrlink) },
81
+ cacheKey: post.data.updated ?? post.data.date,
81
82
  props: { post },
82
83
  }));
83
84
  }) satisfies GetStaticPaths;
@@ -180,10 +180,12 @@ function listPostsTool(): WebMCPTool {
180
180
  description: pick(
181
181
  "分页列出博客的全部已发布文章,返回标题、永久链接(abbrlink)、日期、分类、标签、摘要与文章页 URL。" +
182
182
  "需要浏览全站文章、确认某篇文章的 abbrlink 时使用;不返回正文," +
183
- "只要某篇元信息用 stalux_get_post,读正文请用 stalux_read_post。",
183
+ "只要某篇元信息用 stalux_get_post,读正文请用 stalux_read_post。" +
184
+ "pageSize 建议设 50 一次拿完,减少翻页;页码越界时会自动返回最后一页(clamped 标记)。",
184
185
  "Paginated list of all published posts, returning title, permanent link (abbrlink), date, categories, tags, description and post page URL. " +
185
186
  "Use it to browse the whole blog or find a post's abbrlink; it does not return body content — " +
186
- "use stalux_get_post for one post's metadata, or stalux_read_post for the full body.",
187
+ "use stalux_get_post for one post's metadata, or stalux_read_post for the full body. " +
188
+ "Prefer pageSize 50 to fetch everything in one call; out-of-range pages clamp to the last page (clamped flag).",
187
189
  ),
188
190
  annotations: { readOnlyHint: true, untrustedContentHint: false },
189
191
  inputSchema: {
@@ -222,23 +224,16 @@ function listPostsTool(): WebMCPTool {
222
224
  );
223
225
  const total = list.length;
224
226
  const totalPages = Math.ceil(total / pageSize) || 1;
225
- const start = (page - 1) * pageSize;
226
- if (start >= total) {
227
- return err(
228
- "OUT_OF_RANGE",
229
- pick(
230
- "第 " + page + " 页没有文章(共 " + totalPages + " 页)",
231
- "Page " + page + " has no posts (" + totalPages + " pages total)",
232
- ),
233
- {
234
- page,
235
- totalPages,
236
- total,
237
- },
238
- );
227
+ // 越界时自动回退到最后一页(而非报错),agent 翻过头也能拿到数据
228
+ let clamped = false;
229
+ let resolvedPage = page;
230
+ if (page > totalPages) {
231
+ resolvedPage = totalPages;
232
+ clamped = true;
239
233
  }
234
+ const start = (resolvedPage - 1) * pageSize;
240
235
  const posts = list.slice(start, start + pageSize).map(briefMeta);
241
- return { ok: true, page, pageSize, total, totalPages, posts };
236
+ return { ok: true, page: resolvedPage, pageSize, total, totalPages, clamped, posts };
242
237
  },
243
238
  };
244
239
  }
@@ -32,13 +32,22 @@ export async function buildTaxonomyStaticPaths(key: TaxonomyKey): Promise<GetSta
32
32
  }
33
33
  }
34
34
 
35
- return [...map].map(([name, entry]) => ({
36
- params: { [paramName]: name },
37
- props: {
38
- [paramName]: name,
39
- count: entry.posts.length,
40
- posts: entry.posts,
41
- lastUpdateDate: entry.latestTime,
42
- },
43
- }));
35
+ return [...map].map(([name, entry]) => {
36
+ // 增量构建 cacheKey:该分类/标签下全部文章更新时间拼接,
37
+ // 任一文章新增/编辑/变更分类都会改变列表输出并失效本页
38
+ const cacheKey = entry.posts
39
+ .map((p) => p.data.updated ?? p.data.date)
40
+ .sort()
41
+ .join("|");
42
+ return {
43
+ params: { [paramName]: name },
44
+ cacheKey,
45
+ props: {
46
+ [paramName]: name,
47
+ count: entry.posts.length,
48
+ posts: entry.posts,
49
+ lastUpdateDate: entry.latestTime,
50
+ },
51
+ };
52
+ });
44
53
  }