@trim21/personal-pi-extensions 0.1.612 → 0.1.619

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 (77) hide show
  1. package/package.json +1 -1
  2. package/src/aft/config.ts +9 -3
  3. package/src/aft/index.ts +6 -2
  4. package/src/aft/logger.ts +9 -3
  5. package/src/aft/tools.ts +3 -1
  6. package/src/bwrap/README.md +19 -10
  7. package/src/bwrap/approval-rules.ts +42 -14
  8. package/src/bwrap/approval-suggest.ts +12 -4
  9. package/src/bwrap/core.ts +39 -13
  10. package/src/bwrap/dcg-scan.ts +16 -6
  11. package/src/bwrap/holder.ts +3 -1
  12. package/src/bwrap/mihomo-config.ts +18 -6
  13. package/src/bwrap/network-stack.ts +69 -24
  14. package/src/bwrap/runtime.ts +30 -10
  15. package/src/bwrap/sandbox.ts +1 -1
  16. package/src/claude-code/common.ts +6 -2
  17. package/src/claude-code/edit-utils.ts +3 -1
  18. package/src/claude-code/files.ts +40 -14
  19. package/src/claude-code/glob.ts +12 -4
  20. package/src/claude-code/grep.ts +41 -14
  21. package/src/claude-code/session-tools.ts +18 -6
  22. package/src/claude-code/shell.ts +9 -3
  23. package/src/gh/base.ts +72 -24
  24. package/src/gh/tools/download-release-assets.ts +12 -4
  25. package/src/gh/tools/list-releases.ts +3 -1
  26. package/src/gh/tools/list-workflow-runs.ts +9 -3
  27. package/src/gh/tools/read-ci-logs.ts +21 -7
  28. package/src/gh/tools/read-repo.ts +3 -1
  29. package/src/lib/cli-args.ts +6 -2
  30. package/src/lib/cli.ts +48 -16
  31. package/src/lib/file-reads.ts +24 -8
  32. package/src/lib/github.ts +35 -12
  33. package/src/lib/lsp/adapter.ts +6 -2
  34. package/src/lib/lsp/bin.ts +12 -4
  35. package/src/lib/lsp/client.ts +205 -69
  36. package/src/lib/lsp/diagnostic.ts +6 -2
  37. package/src/lib/lsp/inspect-tool.ts +25 -9
  38. package/src/lib/lsp/lsp.ts +138 -46
  39. package/src/lib/lsp/rename-tool.ts +11 -4
  40. package/src/lib/lsp/rename.ts +25 -8
  41. package/src/lib/lsp/server-config.ts +41 -14
  42. package/src/lib/lsp/watcher.ts +51 -17
  43. package/src/lib/path.ts +18 -6
  44. package/src/lib/proc.ts +3 -1
  45. package/src/lib/proxy.ts +9 -3
  46. package/src/lib/request-policy.ts +3 -1
  47. package/src/lib/seq-state.ts +3 -1
  48. package/src/lib/ui.ts +23 -8
  49. package/src/lib/write-guard.ts +21 -7
  50. package/src/openai-cost/config.ts +3 -1
  51. package/src/openai-cost/cost.ts +54 -18
  52. package/src/openai-cost/index.ts +3 -1
  53. package/src/openai-cost/provider.ts +6 -2
  54. package/src/opencode/bash.ts +9 -3
  55. package/src/opencode/edit-engine.ts +24 -8
  56. package/src/opencode/files.ts +30 -10
  57. package/src/opencode/glob.ts +3 -1
  58. package/src/opencode/grep.ts +12 -4
  59. package/src/opencode/question.ts +3 -1
  60. package/src/opencode/ripgrep.ts +18 -6
  61. package/src/opencode/todo.ts +3 -1
  62. package/src/session-name.ts +39 -13
  63. package/src/spawn-agent-agents.ts +18 -6
  64. package/src/spawn-agent.ts +53 -18
  65. package/src/system-prompt/index.ts +9 -3
  66. package/src/talk/core.ts +143 -48
  67. package/src/talk/format.ts +12 -4
  68. package/src/talk/group.ts +9 -3
  69. package/src/talk/index.ts +30 -10
  70. package/src/talk/mailbox.ts +30 -10
  71. package/src/talk/policy.ts +6 -2
  72. package/src/talk/registry.ts +33 -11
  73. package/src/talk/storage.ts +3 -1
  74. package/src/vision-agent.ts +41 -14
  75. package/src/web/config.ts +3 -1
  76. package/src/web/fetch.ts +75 -25
  77. package/src/web/search.ts +30 -10
@@ -151,8 +151,12 @@ async function retryOnContentModified<T>(fn: () => Promise<T>): Promise<T> {
151
151
  try {
152
152
  return await fn();
153
153
  } catch (error) {
154
- if (!(error instanceof ResponseError && error.code === LSP_CONTENT_MODIFIED)) throw error;
155
- if (attempt >= renameVerificationTiming.contentModifiedRetries) throw error;
154
+ if (!(error instanceof ResponseError && error.code === LSP_CONTENT_MODIFIED)) {
155
+ throw error;
156
+ }
157
+ if (attempt >= renameVerificationTiming.contentModifiedRetries) {
158
+ throw error;
159
+ }
156
160
  }
157
161
  }
158
162
  }
@@ -199,12 +203,16 @@ type DefinitionResult = LspLocation | LspLocation[] | LocationLink | LocationLin
199
203
 
200
204
  /** Location / LocationLink → path + 0-based 坐标;非 file: URI 是服务器的意外行为,跳过。 */
201
205
  function toInspectLocations(result: DefinitionResult): InspectLocation[] {
202
- if (result === null) return [];
206
+ if (result === null) {
207
+ return [];
208
+ }
203
209
  const items = Array.isArray(result) ? result : [result];
204
210
  const locations: InspectLocation[] = [];
205
211
  for (const item of items) {
206
212
  if ("targetUri" in item) {
207
- if (!item.targetUri.startsWith("file:")) continue;
213
+ if (!item.targetUri.startsWith("file:")) {
214
+ continue;
215
+ }
208
216
  const range =
209
217
  (item as Omit<LocationLink, "targetSelectionRange"> & { targetSelectionRange?: Range })
210
218
  .targetSelectionRange ?? item.targetRange;
@@ -214,7 +222,9 @@ function toInspectLocations(result: DefinitionResult): InspectLocation[] {
214
222
  character: range.start.character,
215
223
  });
216
224
  } else {
217
- if (!item.uri.startsWith("file:")) continue;
225
+ if (!item.uri.startsWith("file:")) {
226
+ continue;
227
+ }
218
228
  locations.push({
219
229
  path: normalize(fileURLToPath(item.uri)),
220
230
  line: item.range.start.line,
@@ -230,14 +240,18 @@ const STDERR_TAIL_CHARS = 4_000;
230
240
 
231
241
  /** 展开 Error 的 cause 链为一条 message;流包装错误只包一层,逐层展开即可还原根因。 */
232
242
  function errorChainMessage(error: unknown): string {
233
- if (!(error instanceof Error)) return String(error);
243
+ if (!(error instanceof Error)) {
244
+ return String(error);
245
+ }
234
246
  const parts: string[] = [];
235
247
  let current: unknown = error;
236
248
  while (current instanceof Error && current.message && !parts.includes(current.message)) {
237
249
  parts.push(current.message);
238
250
  current = current.cause;
239
251
  }
240
- if (typeof current === "string" || typeof current === "number") parts.push(String(current));
252
+ if (typeof current === "string" || typeof current === "number") {
253
+ parts.push(String(current));
254
+ }
241
255
  return parts.join(": ");
242
256
  }
243
257
 
@@ -248,9 +262,13 @@ function describeStartupFailure(
248
262
  stderrTail: string,
249
263
  ): string {
250
264
  const parts = [errorChainMessage(error)];
251
- if (exitDescription) parts.push(`server ${exitDescription}`);
265
+ if (exitDescription) {
266
+ parts.push(`server ${exitDescription}`);
267
+ }
252
268
  const stderr = stderrTail.trim();
253
- if (stderr) parts.push(`stderr: ${stderr}`);
269
+ if (stderr) {
270
+ parts.push(`stderr: ${stderr}`);
271
+ }
254
272
  return parts.join("; ");
255
273
  }
256
274
 
@@ -393,14 +411,20 @@ export interface LspClient {
393
411
  export type Info = LspClient;
394
412
 
395
413
  function getFilePath(uri: string): string | undefined {
396
- if (!uri.startsWith("file://")) return undefined;
414
+ if (!uri.startsWith("file://")) {
415
+ return undefined;
416
+ }
397
417
  return normalize(fileURLToPath(uri));
398
418
  }
399
419
 
400
420
  function getSyncKind(capabilities?: ServerCapabilities): number | undefined {
401
- if (!capabilities) return undefined;
421
+ if (!capabilities) {
422
+ return undefined;
423
+ }
402
424
  const sync = capabilities.textDocumentSync;
403
- if (typeof sync === "number") return sync;
425
+ if (typeof sync === "number") {
426
+ return sync;
427
+ }
404
428
  return sync?.change;
405
429
  }
406
430
 
@@ -426,16 +450,22 @@ function dedupeDiagnostics(items: Diagnostic[]): Diagnostic[] {
426
450
  source: item.source,
427
451
  range: item.range,
428
452
  });
429
- if (seen.has(key)) return false;
453
+ if (seen.has(key)) {
454
+ return false;
455
+ }
430
456
  seen.add(key);
431
457
  return true;
432
458
  });
433
459
  }
434
460
 
435
461
  function configurationValue(settings: unknown, section?: string): unknown {
436
- if (!section) return settings ?? null;
462
+ if (!section) {
463
+ return settings ?? null;
464
+ }
437
465
  const result = section.split(".").reduce<unknown>((acc, key) => {
438
- if (!acc || typeof acc !== "object" || !(key in acc)) return;
466
+ if (!acc || typeof acc !== "object" || !(key in acc)) {
467
+ return;
468
+ }
439
469
  return (acc as Record<string, unknown>)[key];
440
470
  }, settings);
441
471
  return result ?? null;
@@ -451,7 +481,9 @@ async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
451
481
  }),
452
482
  ]);
453
483
  } finally {
454
- if (timer) clearTimeout(timer);
484
+ if (timer) {
485
+ clearTimeout(timer);
486
+ }
455
487
  }
456
488
  }
457
489
 
@@ -464,7 +496,9 @@ function abortReason(signal: AbortSignal): Error {
464
496
 
465
497
  /** 可中止的 sleep:中止时以 signal.reason 拒绝,而不是白等到轮询间隔结束。 */
466
498
  function sleepWithSignal(ms: number, signal: AbortSignal | undefined): Promise<void> {
467
- if (!signal) return sleep(ms);
499
+ if (!signal) {
500
+ return sleep(ms);
501
+ }
468
502
  return new Promise<void>((resolve, reject) => {
469
503
  const onAbort = (): void => {
470
504
  clearTimeout(timer);
@@ -486,7 +520,9 @@ function sleepWithSignal(ms: number, signal: AbortSignal | undefined): Promise<v
486
520
  const PULL_RETRY_INTERVAL_MS = 100;
487
521
 
488
522
  function stopProcess(process: LspServerHandle["process"]): Promise<void> {
489
- if (process.exitCode !== null) return Promise.resolve();
523
+ if (process.exitCode !== null) {
524
+ return Promise.resolve();
525
+ }
490
526
  try {
491
527
  process.kill();
492
528
  } catch {
@@ -530,8 +566,11 @@ export function evictionPlan(options: {
530
566
  const stale: string[] = [];
531
567
  const evictable: string[] = [];
532
568
  for (const path of options.order) {
533
- if (!options.isResident(path)) stale.push(path);
534
- else if (!options.isWaiting(path)) evictable.push(path);
569
+ if (!options.isResident(path)) {
570
+ stale.push(path);
571
+ } else if (!options.isWaiting(path)) {
572
+ evictable.push(path);
573
+ }
535
574
  }
536
575
  const excess = options.order.length - stale.length - options.maxOpenDocuments;
537
576
  return { stale, evict: excess > 0 ? evictable.slice(0, excess) : [] };
@@ -591,14 +630,17 @@ export async function create(input: CreateInput): Promise<LspClient> {
591
630
  ]);
592
631
  const updatePushDiagnostics = (filePath: string, next: Diagnostic[]): void => {
593
632
  pushDiagnostics.set(filePath, next);
594
- for (const listener of diagnosticListeners)
633
+ for (const listener of diagnosticListeners) {
595
634
  listener({ path: filePath, serverID: input.serverID });
635
+ }
596
636
  };
597
637
  const updatePullDiagnostics = (filePath: string, next: Diagnostic[]): void => {
598
638
  pullDiagnostics.set(filePath, next);
599
639
  };
600
640
  const emitRegistrationChange = (): void => {
601
- for (const listener of registrationListeners) listener();
641
+ for (const listener of registrationListeners) {
642
+ listener();
643
+ }
602
644
  };
603
645
 
604
646
  // ── LSP 连接处理器 ─────────────────────────────────────────────────────────
@@ -607,7 +649,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
607
649
  "textDocument/publishDiagnostics",
608
650
  (params: { uri: string; version?: number; diagnostics: Diagnostic[] }) => {
609
651
  const filePath = getFilePath(params.uri);
610
- if (!filePath) return;
652
+ if (!filePath) {
653
+ return;
654
+ }
611
655
  // 服务器版本滞后于已发送版本时,该 push 对应的是旧内容(异步重算未完成
612
656
  // 时的迟到结果)。忽略,避免与当前版本结果混淆。
613
657
  const currentVersion = documentVersions.get(filePath);
@@ -615,13 +659,17 @@ export async function create(input: CreateInput): Promise<LspClient> {
615
659
  typeof params.version === "number" &&
616
660
  currentVersion !== undefined &&
617
661
  params.version !== currentVersion;
618
- if (isStalePush) return;
662
+ if (isStalePush) {
663
+ return;
664
+ }
619
665
  published.set(filePath, {
620
666
  at: Date.now(),
621
667
  version: typeof params.version === "number" ? params.version : undefined,
622
668
  });
623
669
  const document = files[filePath];
624
- if (document !== undefined) document.lastPushEmpty = params.diagnostics.length === 0;
670
+ if (document !== undefined) {
671
+ document.lastPushEmpty = params.diagnostics.length === 0;
672
+ }
625
673
  updatePushDiagnostics(filePath, params.diagnostics);
626
674
  },
627
675
  );
@@ -651,7 +699,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
651
699
  changed = true;
652
700
  }
653
701
  }
654
- if (changed) emitRegistrationChange();
702
+ if (changed) {
703
+ emitRegistrationChange();
704
+ }
655
705
  });
656
706
  connection.onRequest("client/unregisterCapability", (params) => {
657
707
  const registrations =
@@ -665,7 +715,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
665
715
  changed = true;
666
716
  }
667
717
  }
668
- if (changed) emitRegistrationChange();
718
+ if (changed) {
719
+ emitRegistrationChange();
720
+ }
669
721
  });
670
722
  connection.onRequest("workspace/workspaceFolders", () => [
671
723
  { name: "workspace", uri: pathToFileURL(input.root).href },
@@ -762,7 +814,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
762
814
  isWaiting: (path) => waitingForDiagnostics.has(path),
763
815
  maxOpenDocuments,
764
816
  });
765
- for (const path of plan.stale) lruOrder.delete(path);
817
+ for (const path of plan.stale) {
818
+ lruOrder.delete(path);
819
+ }
766
820
  for (const path of plan.evict) {
767
821
  lruOrder.delete(path);
768
822
  await connection.sendNotification("textDocument/didClose", {
@@ -794,7 +848,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
794
848
  }
795
849
  }
796
850
 
797
- if (matched && !merged.has(filePath)) merged.set(filePath, []);
851
+ if (matched && !merged.has(filePath)) {
852
+ merged.set(filePath, []);
853
+ }
798
854
  for (const [target, items] of merged) {
799
855
  updatePullDiagnostics(target, dedupeDiagnostics(items));
800
856
  }
@@ -814,7 +870,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
814
870
  }),
815
871
  diagnosticsRequestTimeoutMs,
816
872
  ).catch((error: unknown) => {
817
- if (error instanceof Error && error.message.startsWith("Timeout after")) timedOut = true;
873
+ if (error instanceof Error && error.message.startsWith("Timeout after")) {
874
+ timedOut = true;
875
+ }
818
876
  return null;
819
877
  });
820
878
  if (!report) {
@@ -836,7 +894,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
836
894
  }
837
895
  for (const [uri, related] of Object.entries(report.relatedDocuments ?? {})) {
838
896
  const relatedPath = getFilePath(uri);
839
- if (!relatedPath || !Array.isArray(related.items)) continue;
897
+ if (!relatedPath || !Array.isArray(related.items)) {
898
+ continue;
899
+ }
840
900
  push(relatedPath, related.items);
841
901
  handled = true;
842
902
  matched ||= relatedPath === filePath;
@@ -857,7 +917,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
857
917
  }),
858
918
  diagnosticsRequestTimeoutMs,
859
919
  ).catch((error: unknown) => {
860
- if (error instanceof Error && error.message.startsWith("Timeout after")) timedOut = true;
920
+ if (error instanceof Error && error.message.startsWith("Timeout after")) {
921
+ timedOut = true;
922
+ }
861
923
  return null;
862
924
  });
863
925
  if (!report) {
@@ -868,7 +930,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
868
930
  let matched = false;
869
931
  for (const item of report.items ?? []) {
870
932
  const relatedPath = item.uri ? getFilePath(item.uri) : undefined;
871
- if (!relatedPath || !Array.isArray(item.items)) continue;
933
+ if (!relatedPath || !Array.isArray(item.items)) {
934
+ continue;
935
+ }
872
936
  const existing = byFile.get(relatedPath) ?? [];
873
937
  byFile.set(relatedPath, [...existing, ...item.items]);
874
938
  matched ||= relatedPath === filePath;
@@ -906,15 +970,21 @@ export async function create(input: CreateInput): Promise<LspClient> {
906
970
  requests: Promise<DiagnosticRequestResult>[],
907
971
  done: (results: DiagnosticRequestResult[]) => boolean,
908
972
  ): Promise<PullResult> {
909
- if (requests.length === 0) return { handled: false, matched: false, timedOut: false };
973
+ if (requests.length === 0) {
974
+ return { handled: false, matched: false, timedOut: false };
975
+ }
910
976
 
911
977
  return new Promise<PullResult>((resolve) => {
912
978
  const results: DiagnosticRequestResult[] = [];
913
979
  let pending = requests.length;
914
980
  let resolved = false;
915
981
  const finish = (merged: PullResult, force = false) => {
916
- if (resolved) return;
917
- if (!force && !done(results)) return;
982
+ if (resolved) {
983
+ return;
984
+ }
985
+ if (!force && !done(results)) {
986
+ return;
987
+ }
918
988
  resolved = true;
919
989
  resolve(merged);
920
990
  };
@@ -926,12 +996,16 @@ export async function create(input: CreateInput): Promise<LspClient> {
926
996
  pending -= 1;
927
997
  const merged = mergeResults(filePath, results);
928
998
  finish(merged);
929
- if (pending === 0) finish(merged, true);
999
+ if (pending === 0) {
1000
+ finish(merged, true);
1001
+ }
930
1002
  return;
931
1003
  })
932
1004
  .catch(() => {
933
1005
  pending -= 1;
934
- if (pending === 0) finish(mergeResults(filePath, results), true);
1006
+ if (pending === 0) {
1007
+ finish(mergeResults(filePath, results), true);
1008
+ }
935
1009
  return;
936
1010
  });
937
1011
  }
@@ -942,7 +1016,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
942
1016
  // 慢的 pull 继续在后台合并,不按 identifier 串行。见 opencode PR #23771。
943
1017
  async function requestDocumentDiagnostics(filePath: string): Promise<PullResult> {
944
1018
  const state = documentPullState();
945
- if (!state.supported) return { handled: false, matched: false, timedOut: false };
1019
+ if (!state.supported) {
1020
+ return { handled: false, matched: false, timedOut: false };
1021
+ }
946
1022
  return requestDiagnostics(
947
1023
  filePath,
948
1024
  [
@@ -977,12 +1053,16 @@ export async function create(input: CreateInput): Promise<LspClient> {
977
1053
  }
978
1054
 
979
1055
  function waitForRegistrationChange(timeout: number): Promise<boolean> {
980
- if (timeout <= 0) return Promise.resolve(false);
1056
+ if (timeout <= 0) {
1057
+ return Promise.resolve(false);
1058
+ }
981
1059
  return new Promise<boolean>((resolve) => {
982
1060
  let finished = false;
983
1061
  const timer = setTimeout(() => finish(false), timeout);
984
1062
  const finish = (result: boolean) => {
985
- if (finished) return;
1063
+ if (finished) {
1064
+ return;
1065
+ }
986
1066
  finished = true;
987
1067
  clearTimeout(timer);
988
1068
  registrationListeners.delete(listener);
@@ -999,26 +1079,40 @@ export async function create(input: CreateInput): Promise<LspClient> {
999
1079
  after: number;
1000
1080
  timeout: number;
1001
1081
  }): Promise<boolean> {
1002
- if (request.timeout <= 0) return Promise.resolve(false);
1082
+ if (request.timeout <= 0) {
1083
+ return Promise.resolve(false);
1084
+ }
1003
1085
  return new Promise<boolean>((resolve) => {
1004
1086
  let finished = false;
1005
1087
  let debounceTimer: ReturnType<typeof setTimeout> | undefined;
1006
1088
  const timeoutTimer = setTimeout(() => finish(false), request.timeout);
1007
1089
  const unsub = () => diagnosticListeners.delete(listener);
1008
1090
  const finish = (result: boolean) => {
1009
- if (finished) return;
1091
+ if (finished) {
1092
+ return;
1093
+ }
1010
1094
  finished = true;
1011
- if (debounceTimer) clearTimeout(debounceTimer);
1095
+ if (debounceTimer) {
1096
+ clearTimeout(debounceTimer);
1097
+ }
1012
1098
  clearTimeout(timeoutTimer);
1013
1099
  unsub();
1014
1100
  resolve(result);
1015
1101
  };
1016
1102
  const schedule = () => {
1017
1103
  const hit = published.get(request.path);
1018
- if (!hit) return;
1019
- if (typeof hit.version === "number" && hit.version !== request.version) return;
1020
- if (hit.at < request.after && hit.version !== request.version) return;
1021
- if (debounceTimer) clearTimeout(debounceTimer);
1104
+ if (!hit) {
1105
+ return;
1106
+ }
1107
+ if (typeof hit.version === "number" && hit.version !== request.version) {
1108
+ return;
1109
+ }
1110
+ if (hit.at < request.after && hit.version !== request.version) {
1111
+ return;
1112
+ }
1113
+ if (debounceTimer) {
1114
+ clearTimeout(debounceTimer);
1115
+ }
1022
1116
  debounceTimer = setTimeout(
1023
1117
  () => finish(true),
1024
1118
  Math.max(0, diagnosticsDebounceMs - (Date.now() - hit.at)),
@@ -1026,7 +1120,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1026
1120
  };
1027
1121
 
1028
1122
  const listener = (event: { path: string; serverID: string }) => {
1029
- if (event.path !== request.path || event.serverID !== input.serverID) return;
1123
+ if (event.path !== request.path || event.serverID !== input.serverID) {
1124
+ return;
1125
+ }
1030
1126
  schedule();
1031
1127
  };
1032
1128
  diagnosticListeners.add(listener);
@@ -1051,7 +1147,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1051
1147
  // 耗满整个窗口后得到同样的「无诊断」。
1052
1148
  const known = published.get(request.path);
1053
1149
  const document = files[request.path];
1054
- if (known !== undefined && document !== undefined && known.at >= document.syncedAt) return true;
1150
+ if (known !== undefined && document !== undefined && known.at >= document.syncedAt) {
1151
+ return true;
1152
+ }
1055
1153
 
1056
1154
  const startedAt = request.after ?? Date.now();
1057
1155
  // 「上一份 push 为空」的文档用短安静期(见 clientDefaults.diagnosticsSilentWaitTimeoutMs)。
@@ -1071,9 +1169,13 @@ export async function create(input: CreateInput): Promise<LspClient> {
1071
1169
 
1072
1170
  while (!connectionClosed && !request.signal?.aborted) {
1073
1171
  const remaining = budget - (Date.now() - startedAt);
1074
- if (remaining <= 0) return false;
1172
+ if (remaining <= 0) {
1173
+ return false;
1174
+ }
1075
1175
  const result = await requestDocumentDiagnostics(request.path);
1076
- if (result.matched) return true;
1176
+ if (result.matched) {
1177
+ return true;
1178
+ }
1077
1179
  if (result.timedOut) {
1078
1180
  return await pushWait;
1079
1181
  }
@@ -1084,7 +1186,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1084
1186
  ),
1085
1187
  sleep(Math.min(remaining, PULL_RETRY_INTERVAL_MS)).then(() => "interval" as const),
1086
1188
  ]);
1087
- if (next === "push") return true;
1189
+ if (next === "push") {
1190
+ return true;
1191
+ }
1088
1192
  }
1089
1193
  return false;
1090
1194
  }
@@ -1105,9 +1209,13 @@ export async function create(input: CreateInput): Promise<LspClient> {
1105
1209
 
1106
1210
  while (!connectionClosed && !request.signal?.aborted) {
1107
1211
  const remaining = diagnosticsFullWaitTimeoutMs - (Date.now() - startedAt);
1108
- if (remaining <= 0) return;
1212
+ if (remaining <= 0) {
1213
+ return;
1214
+ }
1109
1215
  const result = await requestFullDiagnostics(request.path);
1110
- if (result.handled || result.matched) return;
1216
+ if (result.handled || result.matched) {
1217
+ return;
1218
+ }
1111
1219
  if (result.timedOut) {
1112
1220
  await pushWait;
1113
1221
  return;
@@ -1119,7 +1227,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1119
1227
  ),
1120
1228
  sleep(Math.min(remaining, PULL_RETRY_INTERVAL_MS)).then(() => "interval" as const),
1121
1229
  ]);
1122
- if (next === "push") return;
1230
+ if (next === "push") {
1231
+ return;
1232
+ }
1123
1233
  }
1124
1234
  }
1125
1235
 
@@ -1206,8 +1316,12 @@ export async function create(input: CreateInput): Promise<LspClient> {
1206
1316
  params: object,
1207
1317
  signal: AbortSignal | undefined,
1208
1318
  ): Promise<T> {
1209
- if (!signal) return await connection.sendRequest<T>(method, params);
1210
- if (signal.aborted) throw abortReason(signal);
1319
+ if (!signal) {
1320
+ return await connection.sendRequest<T>(method, params);
1321
+ }
1322
+ if (signal.aborted) {
1323
+ throw abortReason(signal);
1324
+ }
1211
1325
  const source = new CancellationTokenSource();
1212
1326
  const aborted = Promise.withResolvers<never>();
1213
1327
  // 中止可能恰好在请求已返回之后才触发:那时 race 已经结算,而这个 promise 的
@@ -1276,7 +1390,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1276
1390
  const document = files[resolvedPath];
1277
1391
  if (document !== undefined) {
1278
1392
  // 写后诊断等待中的文档不退场(didClose 可能抹掉本次写入的诊断结果)
1279
- if (waitingForDiagnostics.has(resolvedPath)) continue;
1393
+ if (waitingForDiagnostics.has(resolvedPath)) {
1394
+ continue;
1395
+ }
1280
1396
  // 驻留文档被外部改动:内容一致的自身写入 echo 完全忽略;否则先 didClose
1281
1397
  // 让服务器回落磁盘,再以文件事件通知——不 bump 版本,避免与写后等待竞态。
1282
1398
  if (change.type === "changed") {
@@ -1286,7 +1402,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1286
1402
  } catch {
1287
1403
  // 文件已被删除或不可读:按磁盘状态变化处理
1288
1404
  }
1289
- if (disk === document.text) continue;
1405
+ if (disk === document.text) {
1406
+ continue;
1407
+ }
1290
1408
  }
1291
1409
  await connection.sendNotification("textDocument/didClose", {
1292
1410
  textDocument: { uri: pathToFileURL(resolvedPath).href },
@@ -1299,7 +1417,9 @@ export async function create(input: CreateInput): Promise<LspClient> {
1299
1417
  type: FILE_CHANGE_TYPE[change.type],
1300
1418
  });
1301
1419
  }
1302
- if (notified.length === 0) return;
1420
+ if (notified.length === 0) {
1421
+ return;
1422
+ }
1303
1423
  await connection.sendNotification("workspace/didChangeWatchedFiles", {
1304
1424
  changes: notified,
1305
1425
  });
@@ -1405,17 +1525,25 @@ export async function create(input: CreateInput): Promise<LspClient> {
1405
1525
  }
1406
1526
  throw error;
1407
1527
  }
1408
- if (!prepared) throw notRenameable();
1409
- if (typeof prepared.placeholder === "string") placeholder = prepared.placeholder;
1528
+ if (!prepared) {
1529
+ throw notRenameable();
1530
+ }
1531
+ if (typeof prepared.placeholder === "string") {
1532
+ placeholder = prepared.placeholder;
1533
+ }
1410
1534
  }
1411
1535
 
1412
1536
  let locations: { uri: string }[] | null;
1413
1537
  try {
1414
1538
  locations = await referencesRequest();
1415
1539
  } catch (error) {
1416
- if (!(error instanceof ResponseError && error.code === LSP_METHOD_NOT_FOUND)) throw error;
1540
+ if (!(error instanceof ResponseError && error.code === LSP_METHOD_NOT_FOUND)) {
1541
+ throw error;
1542
+ }
1417
1543
  const edit = await sendRename();
1418
- if (!edit) throw notRenameable();
1544
+ if (!edit) {
1545
+ throw notRenameable();
1546
+ }
1419
1547
  return placeholder === undefined ? { edit } : { edit, placeholder };
1420
1548
  }
1421
1549
 
@@ -1439,18 +1567,26 @@ export async function create(input: CreateInput): Promise<LspClient> {
1439
1567
  const expired = now >= deadline;
1440
1568
  if (stable || expired) {
1441
1569
  const edit = await sendRename();
1442
- if (!edit) throw notRenameable();
1570
+ if (!edit) {
1571
+ throw notRenameable();
1572
+ }
1443
1573
  const editPaths = editFilePaths(edit);
1444
1574
  const missing: string[] = [];
1445
1575
  const extra: string[] = [];
1446
1576
  for (const path of stability.paths) {
1447
- if (!editPaths.has(path)) missing.push(path);
1577
+ if (!editPaths.has(path)) {
1578
+ missing.push(path);
1579
+ }
1448
1580
  }
1449
1581
  for (const path of editPaths) {
1450
- if (!stability.paths.has(path)) extra.push(path);
1582
+ if (!stability.paths.has(path)) {
1583
+ extra.push(path);
1584
+ }
1451
1585
  }
1452
1586
  if (missing.length === 0 && extra.length === 0) {
1453
- if (stable) return placeholder === undefined ? { edit } : { edit, placeholder };
1587
+ if (stable) {
1588
+ return placeholder === undefined ? { edit } : { edit, placeholder };
1589
+ }
1454
1590
  // 双向一致但稳定窗口未达标:索引可能仍在加载、残缺答案假稳定,
1455
1591
  // 宁可报可重试的不完整错误,也不把残缺结果当成功写盘。
1456
1592
  throw new RenameIncompleteError([], []);
@@ -60,7 +60,9 @@ export function report(file: string, issues: Diagnostic[]): DiagnosticReport {
60
60
  const errors = issues.filter((item) => severityOf(item) === 1);
61
61
  const warnings = issues.filter((item) => item.severity === 2);
62
62
  const relevant = [...errors, ...warnings];
63
- if (relevant.length === 0) return EMPTY_DIAGNOSTIC_REPORT;
63
+ if (relevant.length === 0) {
64
+ return EMPTY_DIAGNOSTIC_REPORT;
65
+ }
64
66
  const limited = relevant.slice(0, MAX_PER_FILE);
65
67
  const hidden = relevant.slice(MAX_PER_FILE);
66
68
  const suffix = hidden.length > 0 ? `\n... and ${hiddenSummary(hidden)}` : "";
@@ -73,6 +75,8 @@ export function report(file: string, issues: Diagnostic[]): DiagnosticReport {
73
75
 
74
76
  /** 把 LSP 诊断块接到工具成功文案后面;无诊断时原样返回。 */
75
77
  export function appendLspDiagnosticText(message: string, diagnosticText: string): string {
76
- if (diagnosticText === "") return message;
78
+ if (diagnosticText === "") {
79
+ return message;
80
+ }
77
81
  return `${message}\n\nLSP diagnostics detected in this file\n${diagnosticText}`;
78
82
  }