@jingyi0605/codingns 0.3.5 → 0.4.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.
Files changed (255) hide show
  1. package/README.md +16 -0
  2. package/bin/codingns.mjs +1369 -10
  3. package/dist/public/assets/{TerminalPage-CgrfstRm.js → TerminalPage-6jHZV9Mh.js} +17 -17
  4. package/dist/public/assets/index-CSVhg7I8.js +123 -0
  5. package/dist/public/assets/index-Ce1VX19m.css +1 -0
  6. package/dist/public/index.html +2 -2
  7. package/dist/server/config/opencode-base-url-resolver.d.ts +7 -0
  8. package/dist/server/config/opencode-base-url-resolver.js +48 -11
  9. package/dist/server/config/opencode-base-url-resolver.js.map +1 -1
  10. package/dist/server/config/opencode-system-probe-helper-client.d.ts +4 -0
  11. package/dist/server/config/opencode-system-probe-helper-client.js +29 -0
  12. package/dist/server/config/opencode-system-probe-helper-client.js.map +1 -1
  13. package/dist/server/config/opencode-system-probe-helper-process.d.ts +12 -0
  14. package/dist/server/config/opencode-system-probe-helper-process.js +34 -7
  15. package/dist/server/config/opencode-system-probe-helper-process.js.map +1 -1
  16. package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +317 -0
  17. package/dist/server/modules/assistant-capability/assistant-capability-controller.js +549 -1
  18. package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
  19. package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +330 -2
  20. package/dist/server/modules/assistant-capability/assistant-capability-service.js +958 -3
  21. package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
  22. package/dist/server/modules/butler/assistant-automation-service.d.ts +110 -0
  23. package/dist/server/modules/butler/assistant-automation-service.js +786 -0
  24. package/dist/server/modules/butler/assistant-automation-service.js.map +1 -0
  25. package/dist/server/modules/butler/assistant-automation-trigger.d.ts +94 -0
  26. package/dist/server/modules/butler/assistant-automation-trigger.js +400 -0
  27. package/dist/server/modules/butler/assistant-automation-trigger.js.map +1 -0
  28. package/dist/server/modules/butler/assistant-sandbox-service.d.ts +55 -0
  29. package/dist/server/modules/butler/assistant-sandbox-service.js +266 -0
  30. package/dist/server/modules/butler/assistant-sandbox-service.js.map +1 -0
  31. package/dist/server/modules/butler/butler-action-context-service.d.ts +4 -1
  32. package/dist/server/modules/butler/butler-action-context-service.js +8 -2
  33. package/dist/server/modules/butler/butler-action-context-service.js.map +1 -1
  34. package/dist/server/modules/butler/butler-control-session-service.d.ts +8 -1
  35. package/dist/server/modules/butler/butler-control-session-service.js +154 -40
  36. package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
  37. package/dist/server/modules/butler/butler-control-timer-scheduler.d.ts +32 -0
  38. package/dist/server/modules/butler/butler-control-timer-scheduler.js +93 -0
  39. package/dist/server/modules/butler/butler-control-timer-scheduler.js.map +1 -0
  40. package/dist/server/modules/butler/butler-control-timer-service.d.ts +42 -0
  41. package/dist/server/modules/butler/butler-control-timer-service.js +132 -0
  42. package/dist/server/modules/butler/butler-control-timer-service.js.map +1 -0
  43. package/dist/server/modules/butler/butler-controller.d.ts +42 -2
  44. package/dist/server/modules/butler/butler-controller.js +79 -12
  45. package/dist/server/modules/butler/butler-controller.js.map +1 -1
  46. package/dist/server/modules/butler/butler-follow-up-service.d.ts +9 -1
  47. package/dist/server/modules/butler/butler-follow-up-service.js +273 -181
  48. package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
  49. package/dist/server/modules/butler/butler-inbox-analysis-service.d.ts +4 -1
  50. package/dist/server/modules/butler/butler-inbox-analysis-service.js +18 -4
  51. package/dist/server/modules/butler/butler-inbox-analysis-service.js.map +1 -1
  52. package/dist/server/modules/butler/butler-inbox-instruction-adapter.js +7 -6
  53. package/dist/server/modules/butler/butler-inbox-instruction-adapter.js.map +1 -1
  54. package/dist/server/modules/butler/butler-profile-service.js +2 -5
  55. package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
  56. package/dist/server/modules/butler/butler-project-service.d.ts +3 -1
  57. package/dist/server/modules/butler/butler-project-service.js +7 -1
  58. package/dist/server/modules/butler/butler-project-service.js.map +1 -1
  59. package/dist/server/modules/butler/butler-session-service.d.ts +3 -1
  60. package/dist/server/modules/butler/butler-session-service.js +12 -1
  61. package/dist/server/modules/butler/butler-session-service.js.map +1 -1
  62. package/dist/server/modules/butler/butler-session-summary-service.js +2 -1
  63. package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
  64. package/dist/server/modules/butler/butler-workspace-context.d.ts +3 -0
  65. package/dist/server/modules/butler/butler-workspace-context.js +182 -51
  66. package/dist/server/modules/butler/butler-workspace-context.js.map +1 -1
  67. package/dist/server/modules/butler/patrol-execution-service.js +2 -1
  68. package/dist/server/modules/butler/patrol-execution-service.js.map +1 -1
  69. package/dist/server/modules/butler/provider-adapter-registry.d.ts +3 -0
  70. package/dist/server/modules/butler/provider-adapter-registry.js +18 -1
  71. package/dist/server/modules/butler/provider-adapter-registry.js.map +1 -1
  72. package/dist/server/modules/butler/verification-run-service.d.ts +9 -2
  73. package/dist/server/modules/butler/verification-run-service.js +188 -34
  74. package/dist/server/modules/butler/verification-run-service.js.map +1 -1
  75. package/dist/server/modules/debug-target/debug-target-controller.d.ts +13 -0
  76. package/dist/server/modules/debug-target/debug-target-controller.js +77 -2
  77. package/dist/server/modules/debug-target/debug-target-controller.js.map +1 -1
  78. package/dist/server/modules/debug-target/debug-target-service.d.ts +17 -3
  79. package/dist/server/modules/debug-target/debug-target-service.js +696 -98
  80. package/dist/server/modules/debug-target/debug-target-service.js.map +1 -1
  81. package/dist/server/modules/git/git-command-helper-client.d.ts +3 -0
  82. package/dist/server/modules/git/git-command-helper-client.js +71 -29
  83. package/dist/server/modules/git/git-command-helper-client.js.map +1 -1
  84. package/dist/server/modules/git/git-command-helper-process.js +62 -9
  85. package/dist/server/modules/git/git-command-helper-process.js.map +1 -1
  86. package/dist/server/modules/git/git-command-runner.d.ts +1 -0
  87. package/dist/server/modules/git/git-command-runner.js +44 -1
  88. package/dist/server/modules/git/git-command-runner.js.map +1 -1
  89. package/dist/server/modules/git/git-controller.js +8 -7
  90. package/dist/server/modules/git/git-controller.js.map +1 -1
  91. package/dist/server/modules/git/git-read-service.d.ts +7 -7
  92. package/dist/server/modules/git/git-read-service.js +41 -24
  93. package/dist/server/modules/git/git-read-service.js.map +1 -1
  94. package/dist/server/modules/model-switch/cc-switch-adapter.js +6 -2
  95. package/dist/server/modules/model-switch/cc-switch-adapter.js.map +1 -1
  96. package/dist/server/modules/preferences/profile-service.d.ts +3 -1
  97. package/dist/server/modules/preferences/profile-service.js +74 -3
  98. package/dist/server/modules/preferences/profile-service.js.map +1 -1
  99. package/dist/server/modules/provider/codex-model-options.js +2 -3
  100. package/dist/server/modules/provider/codex-model-options.js.map +1 -1
  101. package/dist/server/modules/provider/opencode-model-options.js +2 -3
  102. package/dist/server/modules/provider/opencode-model-options.js.map +1 -1
  103. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +14 -7
  104. package/dist/server/modules/provider/provider-discovery-helper-client.js +208 -46
  105. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  106. package/dist/server/modules/provider/provider-discovery-helper-process.js +96 -47
  107. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  108. package/dist/server/modules/provider/provider-discovery-runtime.d.ts +4 -0
  109. package/dist/server/modules/provider/provider-discovery-runtime.js +145 -0
  110. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -0
  111. package/dist/server/modules/sessions/claude-runtime-helper-client.js +23 -1
  112. package/dist/server/modules/sessions/claude-runtime-helper-client.js.map +1 -1
  113. package/dist/server/modules/sessions/session-history-service.d.ts +12 -3
  114. package/dist/server/modules/sessions/session-history-service.js +465 -67
  115. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  116. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +8 -0
  117. package/dist/server/modules/sessions/session-live-runtime-service.js +164 -34
  118. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  119. package/dist/server/modules/sessions/session-message-origin-utils.d.ts +12 -0
  120. package/dist/server/modules/sessions/session-message-origin-utils.js +45 -0
  121. package/dist/server/modules/sessions/session-message-origin-utils.js.map +1 -0
  122. package/dist/server/modules/sessions/session-permission-request-service.js +167 -0
  123. package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
  124. package/dist/server/modules/skills/builtin-skill-service.d.ts +12 -0
  125. package/dist/server/modules/skills/builtin-skill-service.js +49 -0
  126. package/dist/server/modules/skills/builtin-skill-service.js.map +1 -0
  127. package/dist/server/modules/skills/builtin-skills/codingns-assistant/SKILL.md +82 -0
  128. package/dist/server/modules/skills/builtin-skills/codingns-assistant/agents/openai.yaml +4 -0
  129. package/dist/server/modules/skills/builtin-skills/codingns-assistant/references/cli-workflow.md +136 -0
  130. package/dist/server/modules/skills/skill-manager-service.d.ts +7 -0
  131. package/dist/server/modules/skills/skill-manager-service.js +98 -0
  132. package/dist/server/modules/skills/skill-manager-service.js.map +1 -1
  133. package/dist/server/modules/tailscale/tailscale-helper-client.d.ts +1 -0
  134. package/dist/server/modules/tailscale/tailscale-helper-client.js +12 -0
  135. package/dist/server/modules/tailscale/tailscale-helper-client.js.map +1 -1
  136. package/dist/server/modules/tasks/task-helper-client.d.ts +10 -2
  137. package/dist/server/modules/tasks/task-helper-client.js +152 -27
  138. package/dist/server/modules/tasks/task-helper-client.js.map +1 -1
  139. package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +10 -3
  140. package/dist/server/modules/tasks/task-helper-process-handlers.js +7 -5
  141. package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -1
  142. package/dist/server/modules/tasks/task-helper-process.js +104 -3
  143. package/dist/server/modules/tasks/task-helper-process.js.map +1 -1
  144. package/dist/server/modules/tasks/task-lane-executors.js +2 -2
  145. package/dist/server/modules/tasks/task-lane-executors.js.map +1 -1
  146. package/dist/server/modules/tasks/task-types.d.ts +4 -0
  147. package/dist/server/modules/tasks/task-types.js +5 -1
  148. package/dist/server/modules/tasks/task-types.js.map +1 -1
  149. package/dist/server/modules/terminal/command-template-service.d.ts +11 -2
  150. package/dist/server/modules/terminal/command-template-service.js +91 -9
  151. package/dist/server/modules/terminal/command-template-service.js.map +1 -1
  152. package/dist/server/modules/terminal/runtime/terminal-log-writer-client.js +1 -1
  153. package/dist/server/modules/terminal/runtime/terminal-log-writer-client.js.map +1 -1
  154. package/dist/server/modules/terminal/runtime/terminal-log-writer-process.js +160 -11
  155. package/dist/server/modules/terminal/runtime/terminal-log-writer-process.js.map +1 -1
  156. package/dist/server/modules/terminal/template-port-runtime.d.ts +1 -1
  157. package/dist/server/modules/terminal/template-port-runtime.js +87 -37
  158. package/dist/server/modules/terminal/template-port-runtime.js.map +1 -1
  159. package/dist/server/modules/terminal/terminal-controller.d.ts +3 -0
  160. package/dist/server/modules/terminal/terminal-controller.js +41 -0
  161. package/dist/server/modules/terminal/terminal-controller.js.map +1 -1
  162. package/dist/server/modules/terminal/terminal-service.d.ts +4 -0
  163. package/dist/server/modules/terminal/terminal-service.js +35 -1
  164. package/dist/server/modules/terminal/terminal-service.js.map +1 -1
  165. package/dist/server/modules/workbench/workbench-service.d.ts +3 -0
  166. package/dist/server/modules/workbench/workbench-service.js +7 -6
  167. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  168. package/dist/server/modules/workbench/workspace-file-watcher.d.ts +14 -6
  169. package/dist/server/modules/workbench/workspace-file-watcher.js +267 -57
  170. package/dist/server/modules/workbench/workspace-file-watcher.js.map +1 -1
  171. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +3 -0
  172. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +149 -41
  173. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  174. package/dist/server/modules/workspace/workspace-code-composition.d.ts +1 -0
  175. package/dist/server/modules/workspace/workspace-code-composition.js +183 -1
  176. package/dist/server/modules/workspace/workspace-code-composition.js.map +1 -1
  177. package/dist/server/modules/workspace/workspace-service.js +54 -17
  178. package/dist/server/modules/workspace/workspace-service.js.map +1 -1
  179. package/dist/server/modules/worktree/worktree-cleanup-service.d.ts +1 -1
  180. package/dist/server/modules/worktree/worktree-cleanup-service.js +22 -17
  181. package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -1
  182. package/dist/server/modules/worktree/worktree-controller.js +6 -5
  183. package/dist/server/modules/worktree/worktree-controller.js.map +1 -1
  184. package/dist/server/modules/worktree/worktree-manager.d.ts +10 -2
  185. package/dist/server/modules/worktree/worktree-manager.js +35 -20
  186. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  187. package/dist/server/modules/worktree/worktree-merge-service.d.ts +2 -2
  188. package/dist/server/modules/worktree/worktree-merge-service.js +34 -27
  189. package/dist/server/modules/worktree/worktree-merge-service.js.map +1 -1
  190. package/dist/server/modules/worktree/worktree-sync-service.d.ts +1 -1
  191. package/dist/server/modules/worktree/worktree-sync-service.js +5 -3
  192. package/dist/server/modules/worktree/worktree-sync-service.js.map +1 -1
  193. package/dist/server/routes/assistant.js +43 -0
  194. package/dist/server/routes/assistant.js.map +1 -1
  195. package/dist/server/routes/butler.js +5 -0
  196. package/dist/server/routes/butler.js.map +1 -1
  197. package/dist/server/server/create-server.d.ts +8 -0
  198. package/dist/server/server/create-server.js +51 -13
  199. package/dist/server/server/create-server.js.map +1 -1
  200. package/dist/server/shared/http/request-abort.d.ts +2 -0
  201. package/dist/server/shared/http/request-abort.js +38 -0
  202. package/dist/server/shared/http/request-abort.js.map +1 -0
  203. package/dist/server/storage/repositories/assistant-automation-run-repository.d.ts +12 -0
  204. package/dist/server/storage/repositories/assistant-automation-run-repository.js +139 -0
  205. package/dist/server/storage/repositories/assistant-automation-run-repository.js.map +1 -0
  206. package/dist/server/storage/repositories/assistant-automation-task-repository.d.ts +15 -0
  207. package/dist/server/storage/repositories/assistant-automation-task-repository.js +173 -0
  208. package/dist/server/storage/repositories/assistant-automation-task-repository.js.map +1 -0
  209. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.d.ts +17 -0
  210. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js +164 -0
  211. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js.map +1 -0
  212. package/dist/server/storage/repositories/butler-control-session-repository.js +27 -3
  213. package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -1
  214. package/dist/server/storage/repositories/butler-control-timer-repository.d.ts +15 -0
  215. package/dist/server/storage/repositories/butler-control-timer-repository.js +157 -0
  216. package/dist/server/storage/repositories/butler-control-timer-repository.js.map +1 -0
  217. package/dist/server/storage/repositories/user-preference-profile-repository.js +6 -3
  218. package/dist/server/storage/repositories/user-preference-profile-repository.js.map +1 -1
  219. package/dist/server/storage/sqlite/client.js +239 -2
  220. package/dist/server/storage/sqlite/client.js.map +1 -1
  221. package/dist/server/storage/sqlite/schema.sql +107 -1
  222. package/dist/server/types/domain.d.ts +89 -2
  223. package/dist/server/ws/workbench-ws-hub.d.ts +14 -7
  224. package/dist/server/ws/workbench-ws-hub.js +316 -158
  225. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  226. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +4 -1
  227. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +111 -3
  228. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
  229. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +6 -1
  230. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +306 -31
  231. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  232. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.d.ts +5 -1
  233. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +187 -26
  234. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -1
  235. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.d.ts +4 -1
  236. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js +98 -1
  237. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js.map +1 -1
  238. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +2 -0
  239. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +71 -8
  240. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
  241. package/node_modules/@codingns/session-sync-core/dist/providers/utils.d.ts +1 -0
  242. package/node_modules/@codingns/session-sync-core/dist/providers/utils.js +4 -1
  243. package/node_modules/@codingns/session-sync-core/dist/providers/utils.js.map +1 -1
  244. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +44 -0
  245. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
  246. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +9 -3
  247. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  248. package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +1 -0
  249. package/node_modules/@codingns/session-sync-core/dist/services.js +17 -8
  250. package/node_modules/@codingns/session-sync-core/dist/services.js.map +1 -1
  251. package/node_modules/@codingns/session-sync-core/dist/types.d.ts +4 -0
  252. package/package.json +1 -1
  253. package/scripts/postinstall.mjs +33 -0
  254. package/dist/public/assets/index-Cek6u0b9.css +0 -1
  255. package/dist/public/assets/index-THHY79si.js +0 -122
@@ -1,8 +1,10 @@
1
1
  import { AppError } from "../shared/errors/app-error.js";
2
2
  import { logTerminalDebug, terminalDebugNowMs } from "../shared/utils/terminal-debug-log.js";
3
3
  const WORKBENCH_REFRESH_INTERVAL_MS = 60_000;
4
- const SIDEBAR_REFRESH_INTERVAL_MS = 5_000;
5
4
  const GIT_SUBSCRIPTION_MIN_REFRESH_INTERVAL_MS = 15_000;
5
+ const GIT_REFRESH_QUIET_WINDOW_MS = 800;
6
+ const TERMINAL_MANAGER_REFRESH_QUIET_WINDOW_MS = 300;
7
+ const WORKSPACE_MANAGEMENT_REFRESH_INTERVAL_MS = 5_000;
6
8
  const WORKBENCH_REALTIME_BROADCAST_DEBOUNCE_MS = 120;
7
9
  const WORKSPACE_MANAGEMENT_TIMER_REFRESH_ENABLED = readBooleanEnv(process.env.CODINGNS_WORKSPACE_MANAGEMENT_AUTO_REFRESH, false);
8
10
  export class WorkbenchWsHub {
@@ -15,12 +17,18 @@ export class WorkbenchWsHub {
15
17
  clientGitSubscriptions = new WeakMap();
16
18
  clientTerminalManagerSubscriptions = new WeakMap();
17
19
  clientWorkspaceManagementSubscriptions = new WeakMap();
18
- constructor(workbenchService, workspacePanelSnapshotService, fileWatcher) {
20
+ constructor(workbenchService, workspacePanelSnapshotService, fileWatcher, terminalService) {
19
21
  this.workbenchService = workbenchService;
20
22
  this.workspacePanelSnapshotService = workspacePanelSnapshotService;
21
23
  this.fileWatcher = fileWatcher;
22
- this.fileWatcher.setOnChange((workspaceId) => {
23
- this.handleWorkspaceFileChange(workspaceId);
24
+ this.fileWatcher.setOnChange((event) => {
25
+ this.handleWorkspaceWatcherChange(event);
26
+ });
27
+ terminalService?.on("status", (terminal) => {
28
+ this.handleTerminalManagerChange(terminal.workspaceId);
29
+ });
30
+ terminalService?.on("exit", ({ terminal }) => {
31
+ this.handleTerminalManagerChange(terminal.workspaceId);
24
32
  });
25
33
  }
26
34
  handleMessage(client, payload, authContext) {
@@ -34,18 +42,15 @@ export class WorkbenchWsHub {
34
42
  switch (message.type) {
35
43
  case "workbench.subscribe":
36
44
  void this.sendWorkbenchSnapshotToClient(client, userId, channel);
45
+ if (this.workbenchService.shouldRefreshSnapshot()) {
46
+ this.workbenchService.scheduleSnapshotRefresh(userId);
47
+ }
37
48
  return true;
38
49
  case "workbench.refresh":
39
- void this.syncTitlesAndBroadcast(userId);
40
50
  void this.refreshAndBroadcast(userId, true);
41
51
  return true;
42
52
  case "fileTree.subscribe":
43
- this.clientFileTreeSubscriptions.set(client, {
44
- workspaceId: message.workspaceId.trim(),
45
- paths: normalizePanelPaths(message.paths),
46
- lastPayloadByPath: new Map()
47
- });
48
- this.fileWatcher.subscribe(message.workspaceId.trim());
53
+ this.replaceFileTreeSubscription(client, message.workspaceId, message.paths);
49
54
  void this.refreshFileTreeSubscriptions(client);
50
55
  return true;
51
56
  case "fileTree.refresh":
@@ -56,39 +61,29 @@ export class WorkbenchWsHub {
56
61
  void this.refreshFileTreeSubscriptions(client, true);
57
62
  return true;
58
63
  case "git.subscribe":
59
- this.clientGitSubscriptions.set(client, {
60
- workspaceId: message.workspaceId.trim(),
61
- lastPayload: null,
62
- lastRequestedAt: 0,
63
- refreshTask: null
64
+ this.ensureGitSubscription(client, message.workspaceId);
65
+ void this.refreshGitSubscription(client, false, {
66
+ deliverIfUnchanged: true,
67
+ ignoreMinInterval: true
64
68
  });
65
- this.fileWatcher.subscribe(message.workspaceId.trim());
66
- void this.refreshGitSubscription(client);
67
69
  return true;
68
70
  case "git.refresh":
69
71
  this.workspacePanelSnapshotService.invalidateGit(message.workspaceId.trim());
70
- this.clientGitSubscriptions.set(client, {
71
- workspaceId: message.workspaceId.trim(),
72
- lastPayload: null,
73
- lastRequestedAt: 0,
74
- refreshTask: null
72
+ this.ensureGitSubscription(client, message.workspaceId);
73
+ this.scheduleGitRefresh(client, {
74
+ force: true
75
75
  });
76
- void this.refreshGitSubscription(client, true);
77
76
  return true;
78
77
  case "terminalManager.subscribe":
79
- this.clientTerminalManagerSubscriptions.set(client, {
80
- workspaceId: message.workspaceId.trim(),
81
- lastPayload: null
82
- });
83
- void this.refreshTerminalManagerSubscription(client);
78
+ this.ensureTerminalManagerSubscription(client, message.workspaceId);
79
+ this.scheduleTerminalManagerRefresh(client);
84
80
  return true;
85
81
  case "terminalManager.refresh":
86
82
  this.workspacePanelSnapshotService.invalidateTerminalManager(message.workspaceId.trim());
87
- this.clientTerminalManagerSubscriptions.set(client, {
88
- workspaceId: message.workspaceId.trim(),
89
- lastPayload: null
83
+ this.ensureTerminalManagerSubscription(client, message.workspaceId);
84
+ this.scheduleTerminalManagerRefresh(client, {
85
+ force: true
90
86
  });
91
- void this.refreshTerminalManagerSubscription(client, true);
92
87
  return true;
93
88
  case "workspaceManagement.subscribe":
94
89
  this.clientWorkspaceManagementSubscriptions.set(client, {
@@ -124,11 +119,19 @@ export class WorkbenchWsHub {
124
119
  // 文件监听器引用计数递减
125
120
  const fileTreeSub = this.clientFileTreeSubscriptions.get(client);
126
121
  if (fileTreeSub) {
127
- this.fileWatcher.unsubscribe(fileTreeSub.workspaceId);
122
+ this.fileWatcher.unsubscribeFileTree(fileTreeSub.workspaceId, fileTreeSub.paths);
128
123
  }
129
124
  const gitSub = this.clientGitSubscriptions.get(client);
130
125
  if (gitSub) {
131
- this.fileWatcher.unsubscribe(gitSub.workspaceId);
126
+ gitSub.refreshController?.abort(new Error("git subscription closed"));
127
+ if (gitSub.refreshTimer) {
128
+ clearTimeout(gitSub.refreshTimer);
129
+ }
130
+ this.fileWatcher.unsubscribeGit(gitSub.workspaceId);
131
+ }
132
+ const terminalManagerSub = this.clientTerminalManagerSubscriptions.get(client);
133
+ if (terminalManagerSub?.refreshTimer) {
134
+ clearTimeout(terminalManagerSub.refreshTimer);
132
135
  }
133
136
  this.clientFileTreeSubscriptions.delete(client);
134
137
  this.clientGitSubscriptions.delete(client);
@@ -140,8 +143,8 @@ export class WorkbenchWsHub {
140
143
  if (channel.workbenchTimer) {
141
144
  clearInterval(channel.workbenchTimer);
142
145
  }
143
- if (channel.sidebarTimer) {
144
- clearInterval(channel.sidebarTimer);
146
+ if (channel.workspaceManagementTimer) {
147
+ clearInterval(channel.workspaceManagementTimer);
145
148
  }
146
149
  if (channel.realtimeBroadcastTimer) {
147
150
  clearTimeout(channel.realtimeBroadcastTimer);
@@ -204,22 +207,42 @@ export class WorkbenchWsHub {
204
207
  channel.clients.add(client);
205
208
  this.clientUsers.set(client, userId);
206
209
  }
207
- /**
208
- * 文件变化回调:chokidar 检测到工作区文件变化后,失效缓存并推送更新给订阅了该工作区的客户端。
209
- */
210
- handleWorkspaceFileChange(workspaceId) {
211
- this.workspacePanelSnapshotService.invalidateFileTree(workspaceId);
212
- this.workspacePanelSnapshotService.invalidateGit(workspaceId);
210
+ handleWorkspaceWatcherChange(event) {
211
+ if (event.scope === "fileTree") {
212
+ this.workspacePanelSnapshotService.invalidateFileTree(event.workspaceId);
213
+ this.workspacePanelSnapshotService.invalidateGit(event.workspaceId);
214
+ }
215
+ else {
216
+ this.workspacePanelSnapshotService.invalidateGit(event.workspaceId);
217
+ }
213
218
  for (const [, channel] of this.userChannels) {
214
219
  for (const client of channel.clients) {
215
220
  const fileTreeSub = this.clientFileTreeSubscriptions.get(client);
216
- if (fileTreeSub && fileTreeSub.workspaceId === workspaceId) {
221
+ if (event.scope === "fileTree" &&
222
+ fileTreeSub &&
223
+ fileTreeSub.workspaceId === event.workspaceId) {
217
224
  void this.refreshFileTreeSubscriptions(client, true);
218
225
  }
219
226
  const gitSub = this.clientGitSubscriptions.get(client);
220
- if (gitSub && gitSub.workspaceId === workspaceId) {
221
- void this.refreshGitSubscription(client, true);
227
+ if (gitSub && gitSub.workspaceId === event.workspaceId) {
228
+ this.scheduleGitRefresh(client, {
229
+ quietWindowMs: GIT_REFRESH_QUIET_WINDOW_MS
230
+ });
231
+ }
232
+ }
233
+ }
234
+ }
235
+ handleTerminalManagerChange(workspaceId) {
236
+ this.workspacePanelSnapshotService.invalidateTerminalManager(workspaceId);
237
+ for (const [, channel] of this.userChannels) {
238
+ for (const client of channel.clients) {
239
+ const subscription = this.clientTerminalManagerSubscriptions.get(client);
240
+ if (!subscription || subscription.workspaceId !== workspaceId) {
241
+ continue;
222
242
  }
243
+ this.scheduleTerminalManagerRefresh(client, {
244
+ quietWindowMs: TERMINAL_MANAGER_REFRESH_QUIET_WINDOW_MS
245
+ });
223
246
  }
224
247
  }
225
248
  }
@@ -232,12 +255,11 @@ export class WorkbenchWsHub {
232
255
  clients: new Set(),
233
256
  lastWorkbenchPayload: null,
234
257
  workbenchTimer: null,
235
- sidebarTimer: null,
258
+ workspaceManagementTimer: null,
236
259
  realtimeBroadcastTimer: null,
237
260
  realtimeBroadcastQueued: false,
238
261
  realtimeBroadcastTask: null,
239
- refreshTask: null,
240
- titleSyncTask: null
262
+ refreshTask: null
241
263
  };
242
264
  channel.workbenchTimer = setInterval(() => {
243
265
  if (!this.workbenchService.shouldRefreshSnapshot()) {
@@ -247,47 +269,16 @@ export class WorkbenchWsHub {
247
269
  this.reportAsyncError("workbenchTimer", error, { userId });
248
270
  });
249
271
  }, WORKBENCH_REFRESH_INTERVAL_MS);
250
- channel.sidebarTimer = setInterval(() => {
251
- void this.refreshSidebarSubscriptions(userId).catch((error) => {
252
- this.reportAsyncError("sidebarTimer", error, { userId });
253
- });
254
- }, SIDEBAR_REFRESH_INTERVAL_MS);
272
+ if (WORKSPACE_MANAGEMENT_TIMER_REFRESH_ENABLED) {
273
+ channel.workspaceManagementTimer = setInterval(() => {
274
+ void this.refreshWorkspaceManagementSubscriptions(userId).catch((error) => {
275
+ this.reportAsyncError("workspaceManagementTimer", error, { userId });
276
+ });
277
+ }, WORKSPACE_MANAGEMENT_REFRESH_INTERVAL_MS);
278
+ }
255
279
  this.userChannels.set(userId, channel);
256
280
  return channel;
257
281
  }
258
- async syncTitlesAndBroadcast(userId) {
259
- const channel = this.getOrCreateChannel(userId);
260
- if (channel.titleSyncTask) {
261
- return channel.titleSyncTask;
262
- }
263
- channel.titleSyncTask = (async () => {
264
- const startedAtMs = terminalDebugNowMs();
265
- try {
266
- const snapshot = await this.workbenchService
267
- .scheduleSessionTitleSync(userId, "workbench_ws.sync_titles")
268
- .promise;
269
- const payload = buildWorkbenchPayload(snapshot);
270
- if (payload === channel.lastWorkbenchPayload) {
271
- return;
272
- }
273
- channel.lastWorkbenchPayload = payload;
274
- for (const client of channel.clients) {
275
- client.send(payload);
276
- }
277
- logTerminalDebug("workbench.sync_titles.completed", {
278
- userId,
279
- clientCount: channel.clients.size,
280
- durationMs: terminalDebugNowMs() - startedAtMs
281
- });
282
- }
283
- catch (error) {
284
- this.reportAsyncError("syncTitlesAndBroadcast", error, { userId });
285
- }
286
- })().finally(() => {
287
- channel.titleSyncTask = null;
288
- });
289
- return channel.titleSyncTask;
290
- }
291
282
  async sendWorkbenchSnapshotToClient(client, userId, channel) {
292
283
  try {
293
284
  const payload = buildWorkbenchPayload(this.workbenchService.getSnapshot(userId));
@@ -334,48 +325,30 @@ export class WorkbenchWsHub {
334
325
  });
335
326
  return channel.refreshTask;
336
327
  }
337
- async refreshSidebarSubscriptions(userId) {
338
- const channel = this.userChannels.get(userId);
339
- if (!channel) {
340
- return;
341
- }
342
- const startedAtMs = terminalDebugNowMs();
343
- await Promise.all([...channel.clients].map(async (client) => {
344
- const refreshTasks = [
345
- this.refreshGitSubscription(client),
346
- this.refreshTerminalManagerSubscription(client)
347
- ];
348
- if (WORKSPACE_MANAGEMENT_TIMER_REFRESH_ENABLED) {
349
- refreshTasks.push(this.refreshWorkspaceManagementSubscription(client));
350
- }
351
- await Promise.allSettled(refreshTasks);
352
- }));
353
- logTerminalDebug("workbench.sidebar_refresh.completed", {
354
- userId,
355
- clientCount: channel.clients.size,
356
- durationMs: terminalDebugNowMs() - startedAtMs
357
- });
358
- }
359
328
  ensureFileTreeSubscription(client, workspaceId, paths) {
360
329
  const current = this.clientFileTreeSubscriptions.get(client);
361
330
  const normalizedWorkspaceId = workspaceId.trim();
362
331
  const normalizedPaths = normalizePanelPaths(paths);
363
- if (!current || current.workspaceId !== normalizedWorkspaceId) {
364
- const next = {
365
- workspaceId: normalizedWorkspaceId,
366
- paths: normalizedPaths,
367
- lastPayloadByPath: new Map()
368
- };
369
- this.clientFileTreeSubscriptions.set(client, next);
370
- return next;
371
- }
372
- if (normalizedPaths.length > 0) {
373
- current.paths = normalizedPaths;
374
- }
375
- if (current.paths.length === 0) {
376
- current.paths = [""];
377
- }
378
- return current;
332
+ const nextPaths = normalizedPaths.length > 0 ? normalizedPaths : [""];
333
+ if (current &&
334
+ current.workspaceId === normalizedWorkspaceId &&
335
+ areStringArraysEqual(current.paths, nextPaths)) {
336
+ return current;
337
+ }
338
+ if (current) {
339
+ this.fileWatcher.unsubscribeFileTree(current.workspaceId, current.paths);
340
+ }
341
+ const next = {
342
+ workspaceId: normalizedWorkspaceId,
343
+ paths: nextPaths,
344
+ lastPayloadByPath: new Map()
345
+ };
346
+ this.clientFileTreeSubscriptions.set(client, next);
347
+ this.fileWatcher.subscribeFileTree(normalizedWorkspaceId, nextPaths);
348
+ return next;
349
+ }
350
+ replaceFileTreeSubscription(client, workspaceId, paths) {
351
+ return this.ensureFileTreeSubscription(client, workspaceId, paths);
379
352
  }
380
353
  async refreshFileTreeSubscriptions(client, force = false) {
381
354
  const subscription = this.clientFileTreeSubscriptions.get(client);
@@ -401,29 +374,47 @@ export class WorkbenchWsHub {
401
374
  });
402
375
  }
403
376
  }
404
- async refreshGitSubscription(client, force = false) {
377
+ async refreshGitSubscription(client, force = false, options) {
405
378
  const subscription = this.clientGitSubscriptions.get(client);
406
379
  if (!subscription) {
407
380
  return;
408
381
  }
409
382
  if (subscription.refreshTask) {
410
- if (!force) {
383
+ subscription.queuedRefresh = true;
384
+ subscription.queuedForce = subscription.queuedForce || force;
385
+ if (!options?.deliverIfUnchanged) {
411
386
  return subscription.refreshTask;
412
387
  }
413
- await subscription.refreshTask;
388
+ return await subscription.refreshTask.finally(() => {
389
+ if (subscription.lastPayload) {
390
+ client.send(subscription.lastPayload);
391
+ }
392
+ });
414
393
  }
415
394
  const now = Date.now();
416
- if (!force
395
+ if (!options?.ignoreMinInterval &&
396
+ !force
417
397
  && now - subscription.lastRequestedAt < GIT_SUBSCRIPTION_MIN_REFRESH_INTERVAL_MS) {
398
+ subscription.queuedRefresh = true;
399
+ subscription.queuedForce = subscription.queuedForce || force;
400
+ this.deferQueuedGitRefresh(client, GIT_SUBSCRIPTION_MIN_REFRESH_INTERVAL_MS - (now - subscription.lastRequestedAt));
418
401
  return;
419
402
  }
420
403
  subscription.lastRequestedAt = now;
404
+ const controller = new AbortController();
405
+ subscription.refreshController = controller;
421
406
  subscription.refreshTask = (async () => {
422
407
  const startedAtMs = terminalDebugNowMs();
423
408
  try {
424
- const snapshot = await this.workspacePanelSnapshotService.getGitPanelSnapshot(subscription.workspaceId, { force });
409
+ const snapshot = await this.workspacePanelSnapshotService.getGitPanelSnapshot(subscription.workspaceId, {
410
+ force,
411
+ signal: controller.signal
412
+ });
413
+ if (controller.signal.aborted) {
414
+ return;
415
+ }
425
416
  const payload = buildGitPayload(snapshot);
426
- if (payload === subscription.lastPayload) {
417
+ if (payload === subscription.lastPayload && !options?.deliverIfUnchanged) {
427
418
  return;
428
419
  }
429
420
  subscription.lastPayload = payload;
@@ -437,48 +428,202 @@ export class WorkbenchWsHub {
437
428
  });
438
429
  }
439
430
  catch (error) {
431
+ if (controller.signal.aborted) {
432
+ return;
433
+ }
440
434
  this.reportAsyncError("refreshGitSubscription", error, {
441
435
  workspaceId: subscription.workspaceId
442
436
  });
443
437
  }
444
438
  })().finally(() => {
445
439
  subscription.refreshTask = null;
440
+ if (subscription.refreshController === controller) {
441
+ subscription.refreshController = null;
442
+ }
443
+ if (subscription.queuedRefresh && !subscription.refreshTimer) {
444
+ this.flushQueuedGitRefresh(client);
445
+ }
446
446
  });
447
447
  return subscription.refreshTask;
448
448
  }
449
- async refreshTerminalManagerSubscription(client, force = false) {
449
+ ensureGitSubscription(client, workspaceId) {
450
+ const normalizedWorkspaceId = workspaceId.trim();
451
+ const current = this.clientGitSubscriptions.get(client);
452
+ if (current && current.workspaceId === normalizedWorkspaceId) {
453
+ return current;
454
+ }
455
+ if (current) {
456
+ current.refreshController?.abort(new Error("git subscription replaced"));
457
+ if (current.refreshTimer) {
458
+ clearTimeout(current.refreshTimer);
459
+ }
460
+ this.fileWatcher.unsubscribeGit(current.workspaceId);
461
+ }
462
+ const next = {
463
+ workspaceId: normalizedWorkspaceId,
464
+ lastPayload: null,
465
+ lastRequestedAt: 0,
466
+ refreshTask: null,
467
+ refreshController: null,
468
+ refreshTimer: null,
469
+ queuedRefresh: false,
470
+ queuedForce: false
471
+ };
472
+ this.clientGitSubscriptions.set(client, next);
473
+ this.fileWatcher.subscribeGit(normalizedWorkspaceId);
474
+ return next;
475
+ }
476
+ scheduleGitRefresh(client, options) {
477
+ const subscription = this.clientGitSubscriptions.get(client);
478
+ if (!subscription) {
479
+ return;
480
+ }
481
+ subscription.queuedRefresh = true;
482
+ subscription.queuedForce = subscription.queuedForce || (options?.force ?? false);
483
+ if (subscription.refreshTimer) {
484
+ clearTimeout(subscription.refreshTimer);
485
+ subscription.refreshTimer = null;
486
+ }
487
+ const quietWindowMs = options?.quietWindowMs ?? 0;
488
+ if (quietWindowMs > 0) {
489
+ this.deferQueuedGitRefresh(client, quietWindowMs);
490
+ return;
491
+ }
492
+ this.flushQueuedGitRefresh(client);
493
+ }
494
+ flushQueuedGitRefresh(client) {
495
+ const subscription = this.clientGitSubscriptions.get(client);
496
+ if (!subscription || subscription.refreshTimer || subscription.refreshTask || !subscription.queuedRefresh) {
497
+ return;
498
+ }
499
+ const force = subscription.queuedForce;
500
+ subscription.queuedRefresh = false;
501
+ subscription.queuedForce = false;
502
+ void this.refreshGitSubscription(client, force);
503
+ }
504
+ deferQueuedGitRefresh(client, delayMs) {
505
+ const subscription = this.clientGitSubscriptions.get(client);
506
+ if (!subscription) {
507
+ return;
508
+ }
509
+ if (subscription.refreshTimer) {
510
+ clearTimeout(subscription.refreshTimer);
511
+ }
512
+ subscription.refreshTimer = setTimeout(() => {
513
+ subscription.refreshTimer = null;
514
+ this.flushQueuedGitRefresh(client);
515
+ }, Math.max(0, delayMs));
516
+ }
517
+ ensureTerminalManagerSubscription(client, workspaceId) {
518
+ const normalizedWorkspaceId = workspaceId.trim();
519
+ const current = this.clientTerminalManagerSubscriptions.get(client);
520
+ if (current && current.workspaceId === normalizedWorkspaceId) {
521
+ return current;
522
+ }
523
+ if (current?.refreshTimer) {
524
+ clearTimeout(current.refreshTimer);
525
+ }
526
+ const next = {
527
+ workspaceId: normalizedWorkspaceId,
528
+ lastPayload: null,
529
+ refreshTask: null,
530
+ refreshTimer: null,
531
+ queuedRefresh: false,
532
+ queuedForce: false
533
+ };
534
+ this.clientTerminalManagerSubscriptions.set(client, next);
535
+ return next;
536
+ }
537
+ scheduleTerminalManagerRefresh(client, options) {
450
538
  const subscription = this.clientTerminalManagerSubscriptions.get(client);
451
539
  if (!subscription) {
452
540
  return;
453
541
  }
454
- try {
455
- const startedAtMs = terminalDebugNowMs();
456
- const snapshot = await this.workspacePanelSnapshotService.getTerminalManagerSnapshot(subscription.workspaceId, { force });
457
- const payloadStartedAtMs = terminalDebugNowMs();
458
- const payload = buildTerminalManagerPayload(snapshot);
459
- const payloadBuildMs = terminalDebugNowMs() - payloadStartedAtMs;
460
- if (payload === subscription.lastPayload) {
461
- return;
462
- }
463
- subscription.lastPayload = payload;
464
- const sendStartedAtMs = terminalDebugNowMs();
465
- client.send(payload);
466
- logTerminalDebug("workbench.terminal_manager_refresh.completed", {
467
- workspaceId: subscription.workspaceId,
468
- force,
469
- terminalCount: snapshot.terminals.length,
470
- templateCount: snapshot.templates.length,
471
- templateStatusCount: snapshot.templateStatuses.length,
472
- payloadBuildMs,
473
- sendMs: terminalDebugNowMs() - sendStartedAtMs,
474
- durationMs: terminalDebugNowMs() - startedAtMs
475
- });
542
+ subscription.queuedRefresh = true;
543
+ subscription.queuedForce = subscription.queuedForce || (options?.force ?? false);
544
+ if (subscription.refreshTimer) {
545
+ clearTimeout(subscription.refreshTimer);
546
+ subscription.refreshTimer = null;
476
547
  }
477
- catch (error) {
478
- this.reportAsyncError("refreshTerminalManagerSubscription", error, {
479
- workspaceId: subscription.workspaceId
480
- });
548
+ const quietWindowMs = options?.quietWindowMs ?? 0;
549
+ if (quietWindowMs > 0) {
550
+ this.deferQueuedTerminalManagerRefresh(client, quietWindowMs);
551
+ return;
552
+ }
553
+ this.flushQueuedTerminalManagerRefresh(client);
554
+ }
555
+ flushQueuedTerminalManagerRefresh(client) {
556
+ const subscription = this.clientTerminalManagerSubscriptions.get(client);
557
+ if (!subscription || subscription.refreshTimer || !subscription.queuedRefresh) {
558
+ return;
559
+ }
560
+ if (subscription.refreshTask) {
561
+ return;
562
+ }
563
+ const force = subscription.queuedForce;
564
+ subscription.queuedRefresh = false;
565
+ subscription.queuedForce = false;
566
+ void this.refreshTerminalManagerSubscription(client, force);
567
+ }
568
+ deferQueuedTerminalManagerRefresh(client, delayMs) {
569
+ const subscription = this.clientTerminalManagerSubscriptions.get(client);
570
+ if (!subscription) {
571
+ return;
572
+ }
573
+ if (subscription.refreshTimer) {
574
+ clearTimeout(subscription.refreshTimer);
575
+ }
576
+ subscription.refreshTimer = setTimeout(() => {
577
+ subscription.refreshTimer = null;
578
+ this.flushQueuedTerminalManagerRefresh(client);
579
+ }, Math.max(0, delayMs));
580
+ }
581
+ async refreshTerminalManagerSubscription(client, force = false) {
582
+ const subscription = this.clientTerminalManagerSubscriptions.get(client);
583
+ if (!subscription) {
584
+ return;
481
585
  }
586
+ if (subscription.refreshTask) {
587
+ subscription.queuedRefresh = true;
588
+ subscription.queuedForce = subscription.queuedForce || force;
589
+ return subscription.refreshTask;
590
+ }
591
+ subscription.refreshTask = (async () => {
592
+ try {
593
+ const startedAtMs = terminalDebugNowMs();
594
+ const snapshot = await this.workspacePanelSnapshotService.getTerminalManagerSnapshot(subscription.workspaceId, { force });
595
+ const payloadStartedAtMs = terminalDebugNowMs();
596
+ const payload = buildTerminalManagerPayload(snapshot);
597
+ const payloadBuildMs = terminalDebugNowMs() - payloadStartedAtMs;
598
+ if (payload === subscription.lastPayload) {
599
+ return;
600
+ }
601
+ subscription.lastPayload = payload;
602
+ const sendStartedAtMs = terminalDebugNowMs();
603
+ client.send(payload);
604
+ logTerminalDebug("workbench.terminal_manager_refresh.completed", {
605
+ workspaceId: subscription.workspaceId,
606
+ force,
607
+ terminalCount: snapshot.terminals.length,
608
+ templateCount: snapshot.templates.length,
609
+ templateStatusCount: snapshot.templateStatuses.length,
610
+ payloadBuildMs,
611
+ sendMs: terminalDebugNowMs() - sendStartedAtMs,
612
+ durationMs: terminalDebugNowMs() - startedAtMs
613
+ });
614
+ }
615
+ catch (error) {
616
+ this.reportAsyncError("refreshTerminalManagerSubscription", error, {
617
+ workspaceId: subscription.workspaceId
618
+ });
619
+ }
620
+ })().finally(() => {
621
+ subscription.refreshTask = null;
622
+ if (subscription.queuedRefresh && !subscription.refreshTimer) {
623
+ this.flushQueuedTerminalManagerRefresh(client);
624
+ }
625
+ });
626
+ return subscription.refreshTask;
482
627
  }
483
628
  async refreshWorkspaceManagementSubscription(client, force = false) {
484
629
  const subscription = this.clientWorkspaceManagementSubscriptions.get(client);
@@ -500,6 +645,13 @@ export class WorkbenchWsHub {
500
645
  });
501
646
  }
502
647
  }
648
+ async refreshWorkspaceManagementSubscriptions(userId) {
649
+ const channel = this.userChannels.get(userId);
650
+ if (!channel) {
651
+ return;
652
+ }
653
+ await Promise.allSettled([...channel.clients].map((client) => this.refreshWorkspaceManagementSubscription(client)));
654
+ }
503
655
  reportAsyncError(scope, error, context = {}) {
504
656
  const appError = error instanceof AppError
505
657
  ? error
@@ -582,6 +734,12 @@ function normalizePanelPaths(paths) {
582
734
  }
583
735
  return [...uniquePaths];
584
736
  }
737
+ function areStringArraysEqual(left, right) {
738
+ if (left.length !== right.length) {
739
+ return false;
740
+ }
741
+ return left.every((value, index) => value === right[index]);
742
+ }
585
743
  function buildWorkbenchPayload(snapshot) {
586
744
  return JSON.stringify({
587
745
  type: "workbench.snapshot",