@jingyi0605/codingns 0.5.5 → 0.6.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 (178) hide show
  1. package/dist/public/assets/{AdaptiveButlerPage-CUyNL98E.js → AdaptiveButlerPage-uFwDdN-F.js} +3 -3
  2. package/dist/public/assets/{App-BFP7LCSC.js → App-BZvapsi8.js} +3 -3
  3. package/dist/public/assets/App-CcDXqFl1.css +1 -0
  4. package/dist/public/assets/{BootstrapPage-G74dX2Us.js → BootstrapPage-gHSoa4JN.js} +1 -1
  5. package/dist/public/assets/ConversationPage-z3sXtKZ7.js +4 -0
  6. package/dist/public/assets/{DesktopDetachPreviewPage-IV7oEdOX.js → DesktopDetachPreviewPage-4eMRxiBW.js} +1 -1
  7. package/dist/public/assets/DesktopWindowPage-CZcoGApB.js +2 -0
  8. package/dist/public/assets/FileContextPanel-C3qex8bb.js +1 -0
  9. package/dist/public/assets/GitSidebar-BK6H16XU.js +6 -0
  10. package/dist/public/assets/{MobileCreateSessionSheet-DqVwz_Hp.js → MobileCreateSessionSheet-BYfbvK8o.js} +1 -1
  11. package/dist/public/assets/MobileSheet-Ckug8hTb.js +1 -0
  12. package/dist/public/assets/{MobileTopHeaderFrame-COTc7cRr.js → MobileTopHeaderFrame-Bwv8Ovm_.js} +1 -1
  13. package/dist/public/assets/MobileWorkspaceSwitcherHeader-RqWrBdn2.js +1 -0
  14. package/dist/public/assets/RelayConnectEntryPage-D_4YL-YH.js +1 -0
  15. package/dist/public/assets/ServerSettingsModal-CMSm3BZU.js +1 -0
  16. package/dist/public/assets/SessionIndexPage-DuK10DL5.js +1 -0
  17. package/dist/public/assets/SettingsPage-fyD-xaHL.js +1 -0
  18. package/dist/public/assets/TerminalManagerPanel-CCLr1Ypk.js +1 -0
  19. package/dist/public/assets/{TerminalPage-DpsvQQVR.js → TerminalPage-DaooFaJ4.js} +19 -19
  20. package/dist/public/assets/{TerminalRuntimeFallbackModal-CNzOt5v5.js → TerminalRuntimeFallbackModal-aUzjEBwP.js} +1 -1
  21. package/dist/public/assets/ToolFilesPage-CGxBvYG0.js +1 -0
  22. package/dist/public/assets/ToolGitPage-C264yjS9.js +1 -0
  23. package/dist/public/assets/ToolProcessesPage-BOP4A1cb.js +1 -0
  24. package/dist/public/assets/ToolsHomePage-CQxGiKQA.js +1 -0
  25. package/dist/public/assets/WorkbenchLandingPage-CvAY68ca.js +1 -0
  26. package/dist/public/assets/WorkbenchLayout-DGm8Tc5M.js +3 -0
  27. package/dist/public/assets/{WorkbenchModal-CbDxaCOR.js → WorkbenchModal-0tPIIhca.js} +1 -1
  28. package/dist/public/assets/{WorkbenchShellRoute-BMcnFadA.css → WorkbenchShellRoute-BF0nHWOk.css} +1 -1
  29. package/dist/public/assets/WorkbenchShellRoute-DBBOsJo9.js +1 -0
  30. package/dist/public/assets/WorkspaceDebugDetailPage-CDerFYd2.js +1 -0
  31. package/dist/public/assets/WorkspaceDetailPage-BlJc1CHE.js +1 -0
  32. package/dist/public/assets/WorkspaceHomePage-BUsKJ3lv.js +1 -0
  33. package/dist/public/assets/client-runtime-manager-BZpL17fc.js +1 -0
  34. package/dist/public/assets/{default-session-permission-mode-Cu5SreTG.js → default-session-permission-mode-DT4SGiwp.js} +1 -1
  35. package/dist/public/assets/{file-tree-icon-BMKuc5pw.js → file-tree-icon-Db5LXC8h.js} +7 -7
  36. package/dist/public/assets/index-BZLcEHW3.js +42 -0
  37. package/dist/public/assets/index-BbspQPC2.css +1 -0
  38. package/dist/public/assets/login-direct-candidate-resolver-1mxe_Oh8.js +1 -0
  39. package/dist/public/assets/{preferences-service-gv_9vGKz.js → preferences-service-DWnzl5a0.js} +1 -1
  40. package/dist/public/assets/relay-entry-C5_Iay0I.js +1 -0
  41. package/dist/public/assets/session-runtime-machine-DdLeDqQr.js +17 -0
  42. package/dist/public/assets/{styles-BWPBZvze.css → styles-CsEMfdaS.css} +1 -1
  43. package/dist/public/assets/{terminal-runtime-meta-B9xJGY__.js → terminal-runtime-meta-cdtWVfCm.js} +1 -1
  44. package/dist/public/assets/{useRegisteredDebugTemplates-CDfl54Wt.js → useRegisteredDebugTemplates-oFAQNIqh.js} +1 -1
  45. package/dist/public/assets/window-BVUB8gMK.js +1 -0
  46. package/dist/public/index.html +2 -2
  47. package/dist/server/config/env.d.ts +1 -0
  48. package/dist/server/config/env.js +3 -0
  49. package/dist/server/config/env.js.map +1 -1
  50. package/dist/server/modules/client/npm-global-package-service.d.ts +7 -1
  51. package/dist/server/modules/client/npm-global-package-service.js +149 -43
  52. package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
  53. package/dist/server/modules/client/service-update-task-service.js +6 -2
  54. package/dist/server/modules/client/service-update-task-service.js.map +1 -1
  55. package/dist/server/modules/client/service-update-types.d.ts +2 -0
  56. package/dist/server/modules/git/git-controller.d.ts +3 -0
  57. package/dist/server/modules/git/git-controller.js +3 -0
  58. package/dist/server/modules/git/git-controller.js.map +1 -1
  59. package/dist/server/modules/git/git-read-service.js +47 -1
  60. package/dist/server/modules/git/git-read-service.js.map +1 -1
  61. package/dist/server/modules/git/git-write-service.d.ts +4 -0
  62. package/dist/server/modules/git/git-write-service.js +24 -0
  63. package/dist/server/modules/git/git-write-service.js.map +1 -1
  64. package/dist/server/modules/git/types.d.ts +1 -0
  65. package/dist/server/modules/git/workspace-repo-guard.d.ts +2 -0
  66. package/dist/server/modules/git/workspace-repo-guard.js +24 -10
  67. package/dist/server/modules/git/workspace-repo-guard.js.map +1 -1
  68. package/dist/server/modules/parallel-sessions/parallel-session-controller.d.ts +53 -0
  69. package/dist/server/modules/parallel-sessions/parallel-session-controller.js +70 -0
  70. package/dist/server/modules/parallel-sessions/parallel-session-controller.js.map +1 -0
  71. package/dist/server/modules/parallel-sessions/parallel-session-group-service.d.ts +83 -0
  72. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js +591 -0
  73. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js.map +1 -0
  74. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.d.ts +56 -0
  75. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js +483 -0
  76. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js.map +1 -0
  77. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.d.ts +2 -0
  78. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js +129 -0
  79. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js.map +1 -0
  80. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js +12 -9
  81. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js.map +1 -1
  82. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +1 -128
  83. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -1
  84. package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +3 -0
  85. package/dist/server/modules/sessions/codex-app-server-helper-client.js +56 -45
  86. package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
  87. package/dist/server/modules/sessions/codex-app-server-helper-process.js +21 -2
  88. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  89. package/dist/server/modules/sessions/session-history-service.d.ts +10 -1
  90. package/dist/server/modules/sessions/session-history-service.js +142 -14
  91. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  92. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +8 -0
  93. package/dist/server/modules/sessions/session-live-runtime-service.js +208 -25
  94. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  95. package/dist/server/modules/workbench/codex-archive-watcher.d.ts +16 -0
  96. package/dist/server/modules/workbench/codex-archive-watcher.js +50 -0
  97. package/dist/server/modules/workbench/codex-archive-watcher.js.map +1 -0
  98. package/dist/server/modules/workbench/workbench-service.d.ts +11 -2
  99. package/dist/server/modules/workbench/workbench-service.js +37 -8
  100. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  101. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +1 -1
  102. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +26 -3
  103. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  104. package/dist/server/modules/workspace/workspace-service.d.ts +3 -1
  105. package/dist/server/modules/workspace/workspace-service.js +10 -2
  106. package/dist/server/modules/workspace/workspace-service.js.map +1 -1
  107. package/dist/server/modules/worktree/worktree-base-ref-resolver.d.ts +20 -0
  108. package/dist/server/modules/worktree/worktree-base-ref-resolver.js +111 -0
  109. package/dist/server/modules/worktree/worktree-base-ref-resolver.js.map +1 -0
  110. package/dist/server/modules/worktree/worktree-cleanup-service.js +9 -3
  111. package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -1
  112. package/dist/server/modules/worktree/worktree-manager.d.ts +0 -1
  113. package/dist/server/modules/worktree/worktree-manager.js +14 -20
  114. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  115. package/dist/server/routes/git.js +1 -0
  116. package/dist/server/routes/git.js.map +1 -1
  117. package/dist/server/routes/parallel-groups.d.ts +3 -0
  118. package/dist/server/routes/parallel-groups.js +9 -0
  119. package/dist/server/routes/parallel-groups.js.map +1 -0
  120. package/dist/server/server/create-server.d.ts +8 -0
  121. package/dist/server/server/create-server.js +38 -4
  122. package/dist/server/server/create-server.js.map +1 -1
  123. package/dist/server/server/workbench-runtime-terminal-sync.d.ts +14 -0
  124. package/dist/server/server/workbench-runtime-terminal-sync.js +17 -0
  125. package/dist/server/server/workbench-runtime-terminal-sync.js.map +1 -0
  126. package/dist/server/storage/repositories/parallel-session-group-repository.d.ts +11 -0
  127. package/dist/server/storage/repositories/parallel-session-group-repository.js +131 -0
  128. package/dist/server/storage/repositories/parallel-session-group-repository.js.map +1 -0
  129. package/dist/server/storage/repositories/parallel-session-member-repository.d.ts +12 -0
  130. package/dist/server/storage/repositories/parallel-session-member-repository.js +150 -0
  131. package/dist/server/storage/repositories/parallel-session-member-repository.js.map +1 -0
  132. package/dist/server/storage/repositories/session-isolated-workspace-repository.d.ts +15 -0
  133. package/dist/server/storage/repositories/session-isolated-workspace-repository.js +230 -0
  134. package/dist/server/storage/repositories/session-isolated-workspace-repository.js.map +1 -0
  135. package/dist/server/storage/sqlite/schema.sql +73 -0
  136. package/dist/server/types/domain.d.ts +72 -0
  137. package/dist/server/ws/workbench-ws-hub.d.ts +3 -1
  138. package/dist/server/ws/workbench-ws-hub.js +23 -4
  139. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  140. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +1 -0
  141. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +34 -0
  142. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  143. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +3 -0
  144. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +46 -22
  145. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
  146. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +488 -281
  147. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  148. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js +29 -5
  149. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js.map +1 -1
  150. package/package.json +1 -1
  151. package/dist/public/assets/App-DUAg5urj.css +0 -1
  152. package/dist/public/assets/ConversationPage-Bz0_tvvM.js +0 -2
  153. package/dist/public/assets/DesktopWindowPage-BBmHyRg5.js +0 -2
  154. package/dist/public/assets/FileContextPanel--FVTxDrq.js +0 -1
  155. package/dist/public/assets/GitSidebar-DAiSi9oc.js +0 -6
  156. package/dist/public/assets/MobileSheet-D1lMrcvD.js +0 -1
  157. package/dist/public/assets/MobileWorkspaceSwitcherHeader-DJPV9ym2.js +0 -1
  158. package/dist/public/assets/RelayConnectEntryPage-dSwU8VzK.js +0 -1
  159. package/dist/public/assets/ServerSettingsModal-B34ms3ze.js +0 -1
  160. package/dist/public/assets/SessionIndexPage-D3tG1gmM.js +0 -1
  161. package/dist/public/assets/SettingsPage-B3-6-5GL.js +0 -1
  162. package/dist/public/assets/TerminalManagerPanel-DhuTEdzV.js +0 -1
  163. package/dist/public/assets/ToolFilesPage-BX9QDi9Y.js +0 -1
  164. package/dist/public/assets/ToolGitPage-4VtFox3p.js +0 -1
  165. package/dist/public/assets/ToolProcessesPage-DZJC6Qnt.js +0 -1
  166. package/dist/public/assets/ToolsHomePage-D7JbrAWv.js +0 -1
  167. package/dist/public/assets/WorkbenchLandingPage-C0yqnzqh.js +0 -1
  168. package/dist/public/assets/WorkbenchLayout-Brlj8K3i.js +0 -3
  169. package/dist/public/assets/WorkbenchShellRoute-puGpdDFY.js +0 -1
  170. package/dist/public/assets/WorkspaceDebugDetailPage-fTGweC9N.js +0 -1
  171. package/dist/public/assets/WorkspaceDetailPage-BtaIzSDB.js +0 -1
  172. package/dist/public/assets/WorkspaceHomePage-CUmmYDrM.js +0 -1
  173. package/dist/public/assets/client-runtime-manager-RHFa_iWo.js +0 -1
  174. package/dist/public/assets/index-Cq3ue0za.css +0 -1
  175. package/dist/public/assets/index-DEbFT-Aq.js +0 -42
  176. package/dist/public/assets/session-runtime-machine-Bfnxkk9B.js +0 -17
  177. package/dist/public/assets/window-BWqRixxq.js +0 -1
  178. /package/dist/public/assets/{styles-CSUx5LGe.js → styles-DRVvx_kv.js} +0 -0
@@ -11,6 +11,7 @@ import { inspectSessionActivity } from "./session-activity-inspector.js";
11
11
  import { SessionActivityAuthorityService } from "./session-activity-authority-service.js";
12
12
  import { mapSessionProviderError } from "./session-provider-error-mapper.js";
13
13
  import { SessionForkRepository } from "../../storage/repositories/session-fork-repository.js";
14
+ import { buildParallelGroupColorToken, resolveParallelDisplayParentSessionId } from "../parallel-sessions/parallel-session-group-service.js";
14
15
  import { enrichClaudeCapabilities } from "../provider/claude-model-options.js";
15
16
  import { CodexModelOptionsService, createFallbackCodexModelOptions, enrichCodexCapabilities } from "../provider/codex-model-options.js";
16
17
  import { OpenCodeModelOptionsService, createFallbackOpenCodeModelOptions, enrichOpenCodeCapabilities } from "../provider/opencode-model-options.js";
@@ -31,6 +32,13 @@ const SESSION_START_DEFERRED_PROVIDERS = new Set([
31
32
  "gemini",
32
33
  "kimi"
33
34
  ]);
35
+ const MUTABLE_HISTORY_TAIL_PROVIDERS = new Set([
36
+ "claude-code",
37
+ "codex",
38
+ "gemini",
39
+ "kimi",
40
+ "opencode"
41
+ ]);
34
42
  const MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS = 1_200;
35
43
  const WORKSPACE_DISCOVERY_BACKGROUND_MAX_AGE_MS = 15_000;
36
44
  const WORKSPACE_DISCOVERY_SCAN_CONCURRENCY = 2;
@@ -62,6 +70,9 @@ export class SessionHistoryService {
62
70
  openCodeModelOptionsService;
63
71
  providerCliCommandPaths;
64
72
  providerCliAvailability;
73
+ parallelSessionGroupRepository;
74
+ parallelSessionMemberRepository;
75
+ sessionIsolatedWorkspaceRepository;
65
76
  providerDiscoveryHelperClient = getSharedProviderDiscoveryHelperClient();
66
77
  providerSessionDiscoveryConfig;
67
78
  taskManager;
@@ -73,7 +84,7 @@ export class SessionHistoryService {
73
84
  sessionDeletedObservers = new Set();
74
85
  workspaceSessionRelations = new Map();
75
86
  workspaceStateRefreshTaskSequence = 0;
76
- constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}, taskManager = createTaskManager()) {
87
+ constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}, taskManager = createTaskManager(), parallelSessionGroupRepository = null, parallelSessionMemberRepository = null, sessionIsolatedWorkspaceRepository = null) {
77
88
  this.db = db;
78
89
  this.workspaceRepository = workspaceRepository;
79
90
  this.sessionBindingRepository = sessionBindingRepository;
@@ -88,6 +99,9 @@ export class SessionHistoryService {
88
99
  this.providerSessionDeleteCli =
89
100
  adapterOverrides.providerSessionDeleteCli ?? new CodingnsProviderSessionDeleteCli(config);
90
101
  this.taskManager = taskManager;
102
+ this.parallelSessionGroupRepository = parallelSessionGroupRepository;
103
+ this.parallelSessionMemberRepository = parallelSessionMemberRepository;
104
+ this.sessionIsolatedWorkspaceRepository = sessionIsolatedWorkspaceRepository;
91
105
  this.claudeCodeHomeDir = config.claudeCodeHomeDir;
92
106
  this.providerCliCommandPaths = {
93
107
  "claude-code": process.platform === "win32" ? "claude.cmd" : "claude",
@@ -423,9 +437,11 @@ export class SessionHistoryService {
423
437
  return this.sessionChangedFileService.listBySessionId(sessionId);
424
438
  }
425
439
  listWorkspaceSessions(workspaceId, userId) {
426
- return this.enrichSessionItems(workspaceId, this.sessionIndexRepository
440
+ const directItems = this.sessionIndexRepository
427
441
  .listByWorkspace(workspaceId, userId)
428
- .filter((item) => !this.isPendingSessionAlias(item)));
442
+ .filter((item) => !this.isPendingSessionAlias(item));
443
+ const projectedItems = this.listProjectedIsolatedWorkspaceSessions(workspaceId, userId);
444
+ return this.enrichSessionItems(workspaceId, sortSessionListItemsByRecentActivity(mergeSessionListItemsBySessionId([...directItems, ...projectedItems])));
429
445
  }
430
446
  getProviderCapabilitiesSnapshot(provider) {
431
447
  try {
@@ -658,7 +674,8 @@ export class SessionHistoryService {
658
674
  }
659
675
  async forkSession(input) {
660
676
  const binding = this.getBindingOrThrow(input.sessionId);
661
- const workspace = this.getWorkspaceOrThrow(binding.workspaceId);
677
+ const targetWorkspaceId = input.targetWorkspaceId?.trim() || binding.workspaceId;
678
+ const workspace = this.getWorkspaceOrThrow(targetWorkspaceId);
662
679
  const targetProvider = input.targetProvider?.trim() || binding.provider;
663
680
  this.assertProviderCapabilityEnabled(targetProvider, "canStartSession", "当前 provider 不支持 fork 创建会话");
664
681
  const sourceMessageId = input.sourceType === "message"
@@ -786,7 +803,7 @@ export class SessionHistoryService {
786
803
  messages: reconstructedMessages
787
804
  });
788
805
  const startedSession = await this.startSessionDirect({
789
- workspaceId: sourceBinding.workspaceId,
806
+ workspaceId: input.targetWorkspaceId?.trim() || sourceBinding.workspaceId,
790
807
  userId: input.userId,
791
808
  provider: input.targetProvider,
792
809
  initialPrompt: inheritedPrompt,
@@ -824,7 +841,7 @@ export class SessionHistoryService {
824
841
  createdAt: timestamp
825
842
  });
826
843
  })();
827
- const relationMap = this.workspaceSessionRelations.get(sourceBinding.workspaceId)
844
+ const relationMap = this.workspaceSessionRelations.get(input.targetWorkspaceId?.trim() || sourceBinding.workspaceId)
828
845
  ?? new Map();
829
846
  relationMap.set(startedSession.sessionId, {
830
847
  parentSessionId: input.sessionId,
@@ -834,7 +851,7 @@ export class SessionHistoryService {
834
851
  isSubagent: startedSession.isSubagent ?? false,
835
852
  subagentLabel: startedSession.subagentLabel ?? null
836
853
  });
837
- this.workspaceSessionRelations.set(sourceBinding.workspaceId, relationMap);
854
+ this.workspaceSessionRelations.set(input.targetWorkspaceId?.trim() || sourceBinding.workspaceId, relationMap);
838
855
  return this.getSessionListItemOrThrow(startedSession.sessionId, input.userId);
839
856
  }
840
857
  async readForkSourceMessages(sessionId, binding, sourceType, sourceMessageId, sourceMessageSnapshot = null) {
@@ -1125,7 +1142,10 @@ export class SessionHistoryService {
1125
1142
  async deleteSession(sessionId, userId) {
1126
1143
  const binding = this.getBindingOrThrow(sessionId);
1127
1144
  const existing = this.getSessionListItemOrThrow(sessionId, userId);
1128
- if (existing.runningState === "starting" || existing.runningState === "running") {
1145
+ const resolvedExisting = existing.runningState === "starting" || existing.runningState === "running"
1146
+ ? await this.refreshRuntimeFallbackSession(sessionId, userId).catch(() => existing)
1147
+ : existing;
1148
+ if (resolvedExisting.runningState === "starting" || resolvedExisting.runningState === "running") {
1129
1149
  throw new AppError({
1130
1150
  statusCode: 409,
1131
1151
  errorCode: "SESSION_DELETE_RUNNING",
@@ -1715,13 +1735,14 @@ export class SessionHistoryService {
1715
1735
  }
1716
1736
  enrichSessionItems(workspaceId, items) {
1717
1737
  const relationMap = this.workspaceSessionRelations.get(workspaceId);
1738
+ const projectionBySessionId = this.buildParallelProjectionBySessionId(items);
1718
1739
  if (!relationMap) {
1719
- return items.map((item) => this.enrichSessionItem(item));
1740
+ return items.map((item) => this.enrichSessionItem(item, projectionBySessionId.get(item.sessionId)));
1720
1741
  }
1721
1742
  return items.map((item) => {
1722
1743
  const relation = relationMap.get(item.sessionId);
1723
1744
  if (!relation) {
1724
- return this.enrichSessionItem(item);
1745
+ return this.enrichSessionItem(item, projectionBySessionId.get(item.sessionId));
1725
1746
  }
1726
1747
  return this.enrichSessionItem({
1727
1748
  ...item,
@@ -1731,10 +1752,12 @@ export class SessionHistoryService {
1731
1752
  annotationSourceText: relation.annotationSourceText,
1732
1753
  isSubagent: relation.isSubagent,
1733
1754
  subagentLabel: relation.subagentLabel
1734
- });
1755
+ }, projectionBySessionId.get(item.sessionId));
1735
1756
  });
1736
1757
  }
1737
- enrichSessionItem(item) {
1758
+ enrichSessionItem(item, projection) {
1759
+ const resolvedProjection = projection
1760
+ ?? this.buildParallelProjectionBySessionId([item]).get(item.sessionId);
1738
1761
  const relation = this.workspaceSessionRelations.get(item.workspaceId)?.get(item.sessionId);
1739
1762
  const nextItem = relation
1740
1763
  ? {
@@ -1756,7 +1779,90 @@ export class SessionHistoryService {
1756
1779
  subagentLabel: item.subagentLabel ?? null
1757
1780
  };
1758
1781
  const resolution = this.sessionActivityAuthorityService.resolvePersistedSession(nextItem);
1759
- return applySessionActivityResolution(nextItem, resolution);
1782
+ return applySessionActivityResolution({
1783
+ ...nextItem,
1784
+ parallelGroup: resolvedProjection?.parallelGroup ?? null,
1785
+ displayParentSessionId: resolvedProjection?.displayParentSessionId ?? null,
1786
+ sessionIsolatedWorkspace: resolvedProjection?.sessionIsolatedWorkspace ?? null
1787
+ }, resolution);
1788
+ }
1789
+ buildParallelProjectionBySessionId(items) {
1790
+ const projectionBySessionId = new Map();
1791
+ if (!this.parallelSessionGroupRepository
1792
+ || !this.parallelSessionMemberRepository
1793
+ || !this.sessionIsolatedWorkspaceRepository
1794
+ || items.length === 0) {
1795
+ return projectionBySessionId;
1796
+ }
1797
+ const sessionIds = items.map((item) => item.sessionId);
1798
+ const members = this.parallelSessionMemberRepository
1799
+ .listBySessionIds(sessionIds)
1800
+ .filter((member) => member.deletedAt === null);
1801
+ if (members.length === 0) {
1802
+ return projectionBySessionId;
1803
+ }
1804
+ const groupIds = [...new Set(members.map((member) => member.groupId))];
1805
+ const groups = this.parallelSessionGroupRepository
1806
+ .listByIds(groupIds)
1807
+ .filter((group) => group.status !== "deleted");
1808
+ const groupById = new Map(groups.map((group) => [group.id, group]));
1809
+ const activeMembersByGroupId = new Map();
1810
+ for (const member of this.parallelSessionMemberRepository.listByGroupIds(groupIds)) {
1811
+ if (member.deletedAt !== null) {
1812
+ continue;
1813
+ }
1814
+ const groupMembers = activeMembersByGroupId.get(member.groupId) ?? [];
1815
+ groupMembers.push(member);
1816
+ activeMembersByGroupId.set(member.groupId, groupMembers);
1817
+ }
1818
+ const isolatedWorkspaceBySessionId = new Map(this.sessionIsolatedWorkspaceRepository
1819
+ .listByOwnerSessionIds(sessionIds)
1820
+ .map((record) => [record.ownerSessionId, record]));
1821
+ for (const member of members) {
1822
+ const group = groupById.get(member.groupId);
1823
+ if (!group) {
1824
+ continue;
1825
+ }
1826
+ const activeMembers = activeMembersByGroupId.get(member.groupId) ?? [member];
1827
+ const isolatedWorkspace = isolatedWorkspaceBySessionId.get(member.sessionId) ?? null;
1828
+ projectionBySessionId.set(member.sessionId, {
1829
+ parallelGroup: {
1830
+ groupId: group.id,
1831
+ role: member.sessionId === group.anchorSessionId ? "anchor" : "member",
1832
+ memberCount: activeMembers.length,
1833
+ sourceType: group.sourceType,
1834
+ sourceSessionId: group.sourceSessionId,
1835
+ anchorSessionId: group.anchorSessionId,
1836
+ colorToken: buildParallelGroupColorToken(group.id)
1837
+ },
1838
+ displayParentSessionId: resolveParallelDisplayParentSessionId(group, member),
1839
+ sessionIsolatedWorkspace: isolatedWorkspace
1840
+ ? {
1841
+ id: isolatedWorkspace.id,
1842
+ workspaceId: isolatedWorkspace.workspaceId,
1843
+ sourceWorkspaceId: isolatedWorkspace.sourceWorkspaceId,
1844
+ branchName: isolatedWorkspace.branchName,
1845
+ lifecycleStatus: isolatedWorkspace.lifecycleStatus,
1846
+ promotedAt: isolatedWorkspace.promotedAt,
1847
+ createdAt: isolatedWorkspace.createdAt,
1848
+ updatedAt: isolatedWorkspace.updatedAt
1849
+ }
1850
+ : null
1851
+ });
1852
+ }
1853
+ return projectionBySessionId;
1854
+ }
1855
+ listProjectedIsolatedWorkspaceSessions(workspaceId, userId) {
1856
+ if (!this.sessionIsolatedWorkspaceRepository) {
1857
+ return [];
1858
+ }
1859
+ return this.sessionIsolatedWorkspaceRepository
1860
+ .listBySourceWorkspaceId(workspaceId)
1861
+ .filter((record) => record.lifecycleStatus === "active"
1862
+ || record.lifecycleStatus === "removing")
1863
+ .map((record) => this.sessionIndexRepository.findBySessionId(record.ownerSessionId, userId))
1864
+ .filter((item) => Boolean(item))
1865
+ .filter((item) => !this.isPendingSessionAlias(item));
1760
1866
  }
1761
1867
  async pullSessionHistory(sessionId, cursor, limit, deliveredMessages, onEnvelope, envelopeType, isClosed = () => false) {
1762
1868
  let currentCursor = cursor;
@@ -3289,7 +3395,7 @@ function createDeliveredHistoryMessageState() {
3289
3395
  };
3290
3396
  }
3291
3397
  function shouldRefreshMutableHistoryTail(provider, page, cursor, deliveredMessages) {
3292
- if (provider !== "kimi" || cursor === null || page.messages.length > 0) {
3398
+ if (!MUTABLE_HISTORY_TAIL_PROVIDERS.has(provider) || cursor === null || page.messages.length > 0) {
3293
3399
  return false;
3294
3400
  }
3295
3401
  return Date.now() - deliveredMessages.lastMutableTailRefreshAtMs >= MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS;
@@ -3545,6 +3651,11 @@ function shouldPreserveRuntimeTerminalState(current, inspection) {
3545
3651
  return inspection.lastEventAt.localeCompare(current.lastEventAt) <= 0;
3546
3652
  }
3547
3653
  if (current.runningState === "starting" || current.runningState === "running") {
3654
+ if (inspection.completedAtCandidate
3655
+ || inspection.errorCode
3656
+ || inspection.runningState === "interrupted") {
3657
+ return false;
3658
+ }
3548
3659
  return inspection.lastEventAt.localeCompare(current.lastEventAt) <= 0;
3549
3660
  }
3550
3661
  return false;
@@ -3772,6 +3883,23 @@ async function runBatchedTransactions(items, batchSize, transaction, logOptions)
3772
3883
  maxBatchMs
3773
3884
  };
3774
3885
  }
3886
+ function mergeSessionListItemsBySessionId(items) {
3887
+ const itemBySessionId = new Map();
3888
+ for (const item of items) {
3889
+ itemBySessionId.set(item.sessionId, item);
3890
+ }
3891
+ return [...itemBySessionId.values()];
3892
+ }
3893
+ function sortSessionListItemsByRecentActivity(items) {
3894
+ return [...items].sort((left, right) => {
3895
+ const leftPrimary = left.lastMessageAt ?? left.updatedAt;
3896
+ const rightPrimary = right.lastMessageAt ?? right.updatedAt;
3897
+ if (leftPrimary !== rightPrimary) {
3898
+ return rightPrimary.localeCompare(leftPrimary);
3899
+ }
3900
+ return right.updatedAt.localeCompare(left.updatedAt);
3901
+ });
3902
+ }
3775
3903
  function applyImmediateModelOptionFallbacks(capabilities, codexSnapshot, openCodeSnapshot) {
3776
3904
  if (capabilities.provider === "codex") {
3777
3905
  return {