@trim21/personal-pi-extensions 0.1.477 → 0.1.478

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": "@trim21/personal-pi-extensions",
3
- "version": "0.1.477",
3
+ "version": "0.1.478",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -63,6 +63,9 @@ function samePaths(a: Set<string>, b: Set<string>): boolean {
63
63
  /** LSP MethodNotFound(-32601):服务器未实现 prepareRename / rename 请求。 */
64
64
  const LSP_METHOD_NOT_FOUND = -32601;
65
65
 
66
+ /** LSP ContentModified(-32801):服务器处理请求期间内容被修改,重发请求即可。 */
67
+ const LSP_CONTENT_MODIFIED = -32801;
68
+
66
69
  /**
67
70
  * 位置不可 rename 或服务器不具备 rename 能力;与传输失败等意外错误区分,
68
71
  * 供调用方在多候选探测时跳过该 client 而不是中断整个操作。
@@ -103,7 +106,27 @@ export class RenameIncompleteError extends Error {
103
106
  * rename 覆盖校验的轮询节奏。budgetMs 是 references 收敛 + 重试的总预算;
104
107
  * 测试可临时缩小以缩短等待。
105
108
  */
106
- export const renameVerificationTiming = { pollMs: 400, budgetMs: 10_000 };
109
+ export const renameVerificationTiming = {
110
+ pollMs: 400,
111
+ budgetMs: 10_000,
112
+ /** ContentModified(-32801) 重试上限:服务器处理期间文档被修改,重发请求即可。 */
113
+ contentModifiedRetries: 3,
114
+ };
115
+
116
+ /**
117
+ * ContentModified 语义:请求处理期间 salsa 数据库被文件变更修改,服务器请
118
+ * 客户端重发请求。重发无副作用,直接重试;仅连续超限才向上抛,避免无限循环。
119
+ */
120
+ async function retryOnContentModified<T>(fn: () => Promise<T>): Promise<T> {
121
+ for (let attempt = 0; ; attempt++) {
122
+ try {
123
+ return await fn();
124
+ } catch (error) {
125
+ if (!(error instanceof ResponseError && error.code === LSP_CONTENT_MODIFIED)) throw error;
126
+ if (attempt >= renameVerificationTiming.contentModifiedRetries) throw error;
127
+ }
128
+ }
129
+ }
107
130
 
108
131
  interface PrepareRenameResponse {
109
132
  range?: unknown;
@@ -984,11 +1007,13 @@ export async function create(input: CreateInput): Promise<LspClient> {
984
1007
  // 服务器不支持 references(MethodNotFound)时跳过校验,信任服务器,
985
1008
  // 与编辑器行为一致。
986
1009
  const referencesRequest = () =>
987
- connection.sendRequest<{ uri: string }[] | null>("textDocument/references", {
988
- textDocument: { uri },
989
- position,
990
- context: { includeDeclaration: true },
991
- });
1010
+ retryOnContentModified(() =>
1011
+ connection.sendRequest<{ uri: string }[] | null>("textDocument/references", {
1012
+ textDocument: { uri },
1013
+ position,
1014
+ context: { includeDeclaration: true },
1015
+ }),
1016
+ );
992
1017
 
993
1018
  const toPaths = (locations: { uri: string }[] | null): Set<string> =>
994
1019
  new Set(
@@ -999,11 +1024,13 @@ export async function create(input: CreateInput): Promise<LspClient> {
999
1024
 
1000
1025
  const sendRename = async (): Promise<WorkspaceEdit | null> => {
1001
1026
  try {
1002
- return await connection.sendRequest<WorkspaceEdit | null>("textDocument/rename", {
1003
- textDocument: { uri },
1004
- position,
1005
- newName: request.newName,
1006
- });
1027
+ return await retryOnContentModified(() =>
1028
+ connection.sendRequest<WorkspaceEdit | null>("textDocument/rename", {
1029
+ textDocument: { uri },
1030
+ position,
1031
+ newName: request.newName,
1032
+ }),
1033
+ );
1007
1034
  } catch (error) {
1008
1035
  if (error instanceof ResponseError && error.code === LSP_METHOD_NOT_FOUND) {
1009
1036
  throw notRenameable();
@@ -1016,9 +1043,11 @@ export async function create(input: CreateInput): Promise<LspClient> {
1016
1043
  if (hasPrepareProvider) {
1017
1044
  let prepared: PrepareRenameResponse | null;
1018
1045
  try {
1019
- prepared = await connection.sendRequest<PrepareRenameResponse | null>(
1020
- "textDocument/prepareRename",
1021
- { textDocument: { uri }, position },
1046
+ prepared = await retryOnContentModified(() =>
1047
+ connection.sendRequest<PrepareRenameResponse | null>("textDocument/prepareRename", {
1048
+ textDocument: { uri },
1049
+ position,
1050
+ }),
1022
1051
  );
1023
1052
  } catch (error) {
1024
1053
  if (error instanceof ResponseError && error.code === LSP_METHOD_NOT_FOUND) {