@jingyi0605/codingns 0.3.6 → 0.5.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 (369) hide show
  1. package/README.md +3 -0
  2. package/bin/codingns.mjs +913 -1
  3. package/dist/public/assets/AdaptiveButlerPage-B153lk5H.css +1 -0
  4. package/dist/public/assets/AdaptiveButlerPage-R-XZw7pd.js +3 -0
  5. package/dist/public/assets/App-DUAg5urj.css +1 -0
  6. package/dist/public/assets/App-DkvE5EyM.js +30 -0
  7. package/dist/public/assets/BootstrapPage-Vu5oEJ8z.js +1 -0
  8. package/dist/public/assets/ConversationPage-Cjpg6g0J.js +2 -0
  9. package/dist/public/assets/DesktopDetachPreviewPage-BgeEqbc5.js +1 -0
  10. package/dist/public/assets/DesktopWindowPage-1WelvxdH.js +2 -0
  11. package/dist/public/assets/FileContextPanel-D_ghXJuW.js +1 -0
  12. package/dist/public/assets/GitSidebar-D9f9Jxwr.js +6 -0
  13. package/dist/public/assets/MobileCreateSessionSheet-DLq5qPkx.js +1 -0
  14. package/dist/public/assets/MobileSheet-DLg-gX1t.js +1 -0
  15. package/dist/public/assets/MobileTopHeaderFrame-DArgZI7L.js +1 -0
  16. package/dist/public/assets/MobileWorkspaceSwitcherHeader-0ywJKfBQ.js +1 -0
  17. package/dist/public/assets/ServerSettingsModal-izoYMx9U.js +1 -0
  18. package/dist/public/assets/SessionIndexPage-C5aG8FIv.js +1 -0
  19. package/dist/public/assets/SettingsPage-HJIC-P-4.js +1 -0
  20. package/dist/public/assets/TerminalManagerPanel-DpyUTo9k.js +1 -0
  21. package/dist/public/assets/{TerminalPage-D00S4KM6.js → TerminalPage-CtKXIU0h.js} +19 -19
  22. package/dist/public/assets/TerminalRuntimeFallbackModal-CRhOQOsT.js +1 -0
  23. package/dist/public/assets/ToolFilesPage-DcYPsS-e.js +1 -0
  24. package/dist/public/assets/ToolGitPage-CsPl89ty.js +1 -0
  25. package/dist/public/assets/ToolProcessesPage-D0dvR8xK.js +1 -0
  26. package/dist/public/assets/ToolsHomePage-4fP-KRiv.js +1 -0
  27. package/dist/public/assets/WorkbenchLandingPage-kvlfyxRo.js +1 -0
  28. package/dist/public/assets/WorkbenchLayout-ByFw4eeu.js +3 -0
  29. package/dist/public/assets/WorkbenchModal-Ctob14VR.js +1 -0
  30. package/dist/public/assets/WorkbenchShellRoute-BUITtdAg.css +1 -0
  31. package/dist/public/assets/WorkbenchShellRoute-Kw7JEZI3.js +1 -0
  32. package/dist/public/assets/WorkspaceDebugDetailPage-Com5kEXJ.js +1 -0
  33. package/dist/public/assets/WorkspaceDetailPage-D0Lrx4Uz.js +1 -0
  34. package/dist/public/assets/WorkspaceHomePage-wR8d3aP9.js +1 -0
  35. package/dist/public/assets/butler-records-events-DgWCG364.js +1 -0
  36. package/dist/public/assets/default-session-permission-mode-CcGwR4Kk.js +1 -0
  37. package/dist/public/assets/event-DvH9tcej.js +1 -0
  38. package/dist/public/assets/file-tree-icon-UFVoVzhM.js +31 -0
  39. package/dist/public/assets/index-Byp9hJ0c.js +42 -0
  40. package/dist/public/assets/index-_52jxu4a.css +1 -0
  41. package/dist/public/assets/preferences-service-KIYeE2gk.js +1 -0
  42. package/dist/public/assets/session-runtime-machine-0KNSSPp5.js +17 -0
  43. package/dist/public/assets/styles-BWPBZvze.css +1 -0
  44. package/dist/public/assets/styles-CSUx5LGe.js +1 -0
  45. package/dist/public/assets/terminal-runtime-meta-AWXJpN4r.js +1 -0
  46. package/dist/public/assets/useRegisteredDebugTemplates-DBDRdptr.js +1 -0
  47. package/dist/public/assets/window-BWqRixxq.js +1 -0
  48. package/dist/public/index.html +2 -2
  49. package/dist/server/middlewares/auth-guard.d.ts +4 -0
  50. package/dist/server/middlewares/auth-guard.js +42 -4
  51. package/dist/server/middlewares/auth-guard.js.map +1 -1
  52. package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +234 -0
  53. package/dist/server/modules/assistant-capability/assistant-capability-controller.js +365 -0
  54. package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
  55. package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +262 -2
  56. package/dist/server/modules/assistant-capability/assistant-capability-service.js +737 -3
  57. package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
  58. package/dist/server/modules/auth/auth-controller.d.ts +11 -1
  59. package/dist/server/modules/auth/auth-controller.js +61 -2
  60. package/dist/server/modules/auth/auth-controller.js.map +1 -1
  61. package/dist/server/modules/auth/auth-device-display-name.d.ts +10 -0
  62. package/dist/server/modules/auth/auth-device-display-name.js +190 -0
  63. package/dist/server/modules/auth/auth-device-display-name.js.map +1 -0
  64. package/dist/server/modules/auth/auth-service.d.ts +80 -5
  65. package/dist/server/modules/auth/auth-service.js +333 -23
  66. package/dist/server/modules/auth/auth-service.js.map +1 -1
  67. package/dist/server/modules/butler/assistant-automation-service.d.ts +112 -0
  68. package/dist/server/modules/butler/assistant-automation-service.js +832 -0
  69. package/dist/server/modules/butler/assistant-automation-service.js.map +1 -0
  70. package/dist/server/modules/butler/assistant-automation-trigger.d.ts +94 -0
  71. package/dist/server/modules/butler/assistant-automation-trigger.js +400 -0
  72. package/dist/server/modules/butler/assistant-automation-trigger.js.map +1 -0
  73. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.d.ts +32 -0
  74. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.js +93 -0
  75. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.js.map +1 -0
  76. package/dist/server/modules/butler/assistant-sandbox-service.d.ts +69 -0
  77. package/dist/server/modules/butler/assistant-sandbox-service.js +399 -0
  78. package/dist/server/modules/butler/assistant-sandbox-service.js.map +1 -0
  79. package/dist/server/modules/butler/butler-action-context-service.d.ts +4 -1
  80. package/dist/server/modules/butler/butler-action-context-service.js +8 -2
  81. package/dist/server/modules/butler/butler-action-context-service.js.map +1 -1
  82. package/dist/server/modules/butler/butler-auth-service.js +7 -2
  83. package/dist/server/modules/butler/butler-auth-service.js.map +1 -1
  84. package/dist/server/modules/butler/butler-control-session-service.d.ts +11 -1
  85. package/dist/server/modules/butler/butler-control-session-service.js +173 -40
  86. package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
  87. package/dist/server/modules/butler/butler-control-timer-scheduler.d.ts +32 -0
  88. package/dist/server/modules/butler/butler-control-timer-scheduler.js +93 -0
  89. package/dist/server/modules/butler/butler-control-timer-scheduler.js.map +1 -0
  90. package/dist/server/modules/butler/butler-control-timer-service.d.ts +42 -0
  91. package/dist/server/modules/butler/butler-control-timer-service.js +132 -0
  92. package/dist/server/modules/butler/butler-control-timer-service.js.map +1 -0
  93. package/dist/server/modules/butler/butler-controller.d.ts +42 -2
  94. package/dist/server/modules/butler/butler-controller.js +79 -12
  95. package/dist/server/modules/butler/butler-controller.js.map +1 -1
  96. package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.d.ts +2 -1
  97. package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js +27 -25
  98. package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js.map +1 -1
  99. package/dist/server/modules/butler/butler-follow-up-service.d.ts +41 -5
  100. package/dist/server/modules/butler/butler-follow-up-service.js +568 -371
  101. package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
  102. package/dist/server/modules/butler/butler-inbox-analysis-service.d.ts +4 -1
  103. package/dist/server/modules/butler/butler-inbox-analysis-service.js +18 -4
  104. package/dist/server/modules/butler/butler-inbox-analysis-service.js.map +1 -1
  105. package/dist/server/modules/butler/butler-inbox-service.js +1 -0
  106. package/dist/server/modules/butler/butler-inbox-service.js.map +1 -1
  107. package/dist/server/modules/butler/butler-profile-service.js +2 -5
  108. package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
  109. package/dist/server/modules/butler/butler-project-service.d.ts +3 -1
  110. package/dist/server/modules/butler/butler-project-service.js +7 -1
  111. package/dist/server/modules/butler/butler-project-service.js.map +1 -1
  112. package/dist/server/modules/butler/butler-session-service.d.ts +5 -1
  113. package/dist/server/modules/butler/butler-session-service.js +26 -1
  114. package/dist/server/modules/butler/butler-session-service.js.map +1 -1
  115. package/dist/server/modules/butler/butler-session-summary-service.js +2 -1
  116. package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
  117. package/dist/server/modules/butler/butler-workspace-context.d.ts +4 -1
  118. package/dist/server/modules/butler/butler-workspace-context.js +204 -58
  119. package/dist/server/modules/butler/butler-workspace-context.js.map +1 -1
  120. package/dist/server/modules/butler/patrol-execution-service.js +2 -1
  121. package/dist/server/modules/butler/patrol-execution-service.js.map +1 -1
  122. package/dist/server/modules/butler/provider-adapter-registry.d.ts +3 -0
  123. package/dist/server/modules/butler/provider-adapter-registry.js +18 -1
  124. package/dist/server/modules/butler/provider-adapter-registry.js.map +1 -1
  125. package/dist/server/modules/butler/verification-run-service.d.ts +9 -2
  126. package/dist/server/modules/butler/verification-run-service.js +188 -34
  127. package/dist/server/modules/butler/verification-run-service.js.map +1 -1
  128. package/dist/server/modules/debug-target/debug-target-controller.js +1 -1
  129. package/dist/server/modules/debug-target/debug-target-controller.js.map +1 -1
  130. package/dist/server/modules/debug-target/debug-target-service.d.ts +7 -2
  131. package/dist/server/modules/debug-target/debug-target-service.js +563 -100
  132. package/dist/server/modules/debug-target/debug-target-service.js.map +1 -1
  133. package/dist/server/modules/git/git-command-helper-client.d.ts +1 -0
  134. package/dist/server/modules/git/git-command-helper-client.js +19 -26
  135. package/dist/server/modules/git/git-command-helper-client.js.map +1 -1
  136. package/dist/server/modules/git/git-command-runner.js +19 -1
  137. package/dist/server/modules/git/git-command-runner.js.map +1 -1
  138. package/dist/server/modules/preferences/profile-service.d.ts +3 -1
  139. package/dist/server/modules/preferences/profile-service.js +74 -3
  140. package/dist/server/modules/preferences/profile-service.js.map +1 -1
  141. package/dist/server/modules/provider/provider-controller.d.ts +1 -1
  142. package/dist/server/modules/provider/provider-controller.js.map +1 -1
  143. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +5 -3
  144. package/dist/server/modules/provider/provider-discovery-helper-client.js +129 -43
  145. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  146. package/dist/server/modules/provider/provider-discovery-helper-process.js +44 -0
  147. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  148. package/dist/server/modules/provider/provider-discovery-runtime.js +83 -3
  149. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
  150. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-identity-service.d.ts +10 -0
  151. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-identity-service.js +48 -0
  152. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-identity-service.js.map +1 -0
  153. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-packets.d.ts +48 -0
  154. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-packets.js +11 -0
  155. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-packets.js.map +1 -0
  156. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-protocol.d.ts +74 -0
  157. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-protocol.js +302 -0
  158. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-protocol.js.map +1 -0
  159. package/dist/server/modules/relay-tunnel/relay-tunnel-controller.d.ts +33 -0
  160. package/dist/server/modules/relay-tunnel/relay-tunnel-controller.js +57 -0
  161. package/dist/server/modules/relay-tunnel/relay-tunnel-controller.js.map +1 -0
  162. package/dist/server/modules/relay-tunnel/relay-tunnel-edge-proof.d.ts +9 -0
  163. package/dist/server/modules/relay-tunnel/relay-tunnel-edge-proof.js +25 -0
  164. package/dist/server/modules/relay-tunnel/relay-tunnel-edge-proof.js.map +1 -0
  165. package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.d.ts +18 -0
  166. package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.js +230 -0
  167. package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.js.map +1 -0
  168. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.d.ts +41 -0
  169. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js +443 -0
  170. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js.map +1 -0
  171. package/dist/server/modules/relay-tunnel/relay-tunnel-service.d.ts +111 -0
  172. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +771 -0
  173. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -0
  174. package/dist/server/modules/sessions/claude-runtime-helper-client.js +23 -1
  175. package/dist/server/modules/sessions/claude-runtime-helper-client.js.map +1 -1
  176. package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +2 -1
  177. package/dist/server/modules/sessions/codex-app-server-helper-client.js +78 -0
  178. package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
  179. package/dist/server/modules/sessions/codex-app-server-helper-process.js +84 -2
  180. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  181. package/dist/server/modules/sessions/provider-session-delete-cli.d.ts +15 -0
  182. package/dist/server/modules/sessions/provider-session-delete-cli.js +148 -0
  183. package/dist/server/modules/sessions/provider-session-delete-cli.js.map +1 -0
  184. package/dist/server/modules/sessions/session-controller.d.ts +4 -1
  185. package/dist/server/modules/sessions/session-controller.js +4 -0
  186. package/dist/server/modules/sessions/session-controller.js.map +1 -1
  187. package/dist/server/modules/sessions/session-history-service.d.ts +24 -1
  188. package/dist/server/modules/sessions/session-history-service.js +401 -42
  189. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  190. package/dist/server/modules/sessions/session-live-runtime-router-service.d.ts +25 -0
  191. package/dist/server/modules/sessions/session-live-runtime-router-service.js +42 -0
  192. package/dist/server/modules/sessions/session-live-runtime-router-service.js.map +1 -0
  193. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +6 -0
  194. package/dist/server/modules/sessions/session-live-runtime-service.js +130 -28
  195. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  196. package/dist/server/modules/sessions/session-message-attachment-service.d.ts +1 -0
  197. package/dist/server/modules/sessions/session-message-attachment-service.js +22 -0
  198. package/dist/server/modules/sessions/session-message-attachment-service.js.map +1 -1
  199. package/dist/server/modules/sessions/session-message-origin-utils.d.ts +12 -0
  200. package/dist/server/modules/sessions/session-message-origin-utils.js +45 -0
  201. package/dist/server/modules/sessions/session-message-origin-utils.js.map +1 -0
  202. package/dist/server/modules/sessions/session-permission-request-service.d.ts +1 -0
  203. package/dist/server/modules/sessions/session-permission-request-service.js +367 -5
  204. package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
  205. package/dist/server/modules/sessions/session-provider-error-mapper.js +32 -0
  206. package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
  207. package/dist/server/modules/sessions/session-provider-usage-guard-service.d.ts +37 -0
  208. package/dist/server/modules/sessions/session-provider-usage-guard-service.js +179 -0
  209. package/dist/server/modules/sessions/session-provider-usage-guard-service.js.map +1 -0
  210. package/dist/server/modules/sessions/session-provider-usage-limit.d.ts +17 -0
  211. package/dist/server/modules/sessions/session-provider-usage-limit.js +465 -0
  212. package/dist/server/modules/sessions/session-provider-usage-limit.js.map +1 -0
  213. package/dist/server/modules/skills/assistant-runtime-skill-catalog.d.ts +8 -0
  214. package/dist/server/modules/skills/assistant-runtime-skill-catalog.js +26 -0
  215. package/dist/server/modules/skills/assistant-runtime-skill-catalog.js.map +1 -0
  216. package/dist/server/modules/skills/assistant-runtime-skill-cleanup.d.ts +9 -0
  217. package/dist/server/modules/skills/assistant-runtime-skill-cleanup.js +55 -0
  218. package/dist/server/modules/skills/assistant-runtime-skill-cleanup.js.map +1 -0
  219. package/dist/server/modules/skills/builtin-skill-service.js +1 -6
  220. package/dist/server/modules/skills/builtin-skill-service.js.map +1 -1
  221. package/dist/server/modules/skills/builtin-skills/codingns-assistant/SKILL.md +19 -12
  222. package/dist/server/modules/skills/builtin-skills/codingns-assistant/references/cli-workflow.md +9 -3
  223. package/dist/server/modules/skills/skill-controller.d.ts +2 -2
  224. package/dist/server/modules/skills/skill-controller.js +9 -1
  225. package/dist/server/modules/skills/skill-controller.js.map +1 -1
  226. package/dist/server/modules/skills/skill-manager-service.d.ts +26 -1
  227. package/dist/server/modules/skills/skill-manager-service.js +346 -90
  228. package/dist/server/modules/skills/skill-manager-service.js.map +1 -1
  229. package/dist/server/modules/skills/skill-name-policy.d.ts +2 -0
  230. package/dist/server/modules/skills/skill-name-policy.js +10 -0
  231. package/dist/server/modules/skills/skill-name-policy.js.map +1 -0
  232. package/dist/server/modules/tailscale/tailscale-service.d.ts +2 -0
  233. package/dist/server/modules/tailscale/tailscale-service.js +21 -8
  234. package/dist/server/modules/tailscale/tailscale-service.js.map +1 -1
  235. package/dist/server/modules/tasks/task-helper-client.d.ts +5 -2
  236. package/dist/server/modules/tasks/task-helper-client.js +118 -38
  237. package/dist/server/modules/tasks/task-helper-client.js.map +1 -1
  238. package/dist/server/modules/tasks/task-helper-process.js +94 -3
  239. package/dist/server/modules/tasks/task-helper-process.js.map +1 -1
  240. package/dist/server/modules/tasks/task-types.d.ts +6 -0
  241. package/dist/server/modules/tasks/task-types.js +7 -1
  242. package/dist/server/modules/tasks/task-types.js.map +1 -1
  243. package/dist/server/modules/terminal/command-template-service.d.ts +9 -0
  244. package/dist/server/modules/terminal/command-template-service.js +87 -5
  245. package/dist/server/modules/terminal/command-template-service.js.map +1 -1
  246. package/dist/server/modules/terminal/template-reverse-proxy-service.js +71 -3
  247. package/dist/server/modules/terminal/template-reverse-proxy-service.js.map +1 -1
  248. package/dist/server/modules/terminal/terminal-controller.d.ts +3 -0
  249. package/dist/server/modules/terminal/terminal-controller.js +41 -0
  250. package/dist/server/modules/terminal/terminal-controller.js.map +1 -1
  251. package/dist/server/modules/workbench/workbench-service.d.ts +3 -0
  252. package/dist/server/modules/workbench/workbench-service.js +4 -3
  253. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  254. package/dist/server/modules/workbench/workspace-file-watcher.d.ts +14 -6
  255. package/dist/server/modules/workbench/workspace-file-watcher.js +267 -57
  256. package/dist/server/modules/workbench/workspace-file-watcher.js.map +1 -1
  257. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +2 -0
  258. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +32 -3
  259. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  260. package/dist/server/modules/worktree/worktree-manager.d.ts +9 -1
  261. package/dist/server/modules/worktree/worktree-manager.js +9 -1
  262. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  263. package/dist/server/routes/assistant.js +49 -0
  264. package/dist/server/routes/assistant.js.map +1 -1
  265. package/dist/server/routes/auth.js +4 -0
  266. package/dist/server/routes/auth.js.map +1 -1
  267. package/dist/server/routes/butler.js +5 -0
  268. package/dist/server/routes/butler.js.map +1 -1
  269. package/dist/server/routes/sessions.js +1 -0
  270. package/dist/server/routes/sessions.js.map +1 -1
  271. package/dist/server/routes/system.d.ts +2 -1
  272. package/dist/server/routes/system.js +13 -1
  273. package/dist/server/routes/system.js.map +1 -1
  274. package/dist/server/server/create-server.d.ts +18 -0
  275. package/dist/server/server/create-server.js +113 -20
  276. package/dist/server/server/create-server.js.map +1 -1
  277. package/dist/server/shared/utils/tokens.d.ts +3 -1
  278. package/dist/server/shared/utils/tokens.js +9 -2
  279. package/dist/server/shared/utils/tokens.js.map +1 -1
  280. package/dist/server/storage/repositories/assistant-automation-run-repository.d.ts +12 -0
  281. package/dist/server/storage/repositories/assistant-automation-run-repository.js +139 -0
  282. package/dist/server/storage/repositories/assistant-automation-run-repository.js.map +1 -0
  283. package/dist/server/storage/repositories/assistant-automation-task-repository.d.ts +17 -0
  284. package/dist/server/storage/repositories/assistant-automation-task-repository.js +179 -0
  285. package/dist/server/storage/repositories/assistant-automation-task-repository.js.map +1 -0
  286. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.d.ts +18 -0
  287. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js +191 -0
  288. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js.map +1 -0
  289. package/dist/server/storage/repositories/auth-device-repository.d.ts +22 -0
  290. package/dist/server/storage/repositories/auth-device-repository.js +97 -0
  291. package/dist/server/storage/repositories/auth-device-repository.js.map +1 -0
  292. package/dist/server/storage/repositories/auth-device-session-repository.d.ts +17 -0
  293. package/dist/server/storage/repositories/auth-device-session-repository.js +82 -0
  294. package/dist/server/storage/repositories/auth-device-session-repository.js.map +1 -0
  295. package/dist/server/storage/repositories/auth-login-event-repository.d.ts +9 -0
  296. package/dist/server/storage/repositories/auth-login-event-repository.js +53 -0
  297. package/dist/server/storage/repositories/auth-login-event-repository.js.map +1 -0
  298. package/dist/server/storage/repositories/auth-token-repository.d.ts +4 -0
  299. package/dist/server/storage/repositories/auth-token-repository.js +58 -5
  300. package/dist/server/storage/repositories/auth-token-repository.js.map +1 -1
  301. package/dist/server/storage/repositories/butler-control-session-repository.js +27 -3
  302. package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -1
  303. package/dist/server/storage/repositories/butler-control-timer-repository.d.ts +15 -0
  304. package/dist/server/storage/repositories/butler-control-timer-repository.js +157 -0
  305. package/dist/server/storage/repositories/butler-control-timer-repository.js.map +1 -0
  306. package/dist/server/storage/repositories/butler-follow-up-task-repository.js +21 -3
  307. package/dist/server/storage/repositories/butler-follow-up-task-repository.js.map +1 -1
  308. package/dist/server/storage/repositories/instance-relay-tunnel-identity-repository.d.ts +8 -0
  309. package/dist/server/storage/repositories/instance-relay-tunnel-identity-repository.js +52 -0
  310. package/dist/server/storage/repositories/instance-relay-tunnel-identity-repository.js.map +1 -0
  311. package/dist/server/storage/repositories/instance-relay-tunnel-repository.d.ts +10 -0
  312. package/dist/server/storage/repositories/instance-relay-tunnel-repository.js +153 -0
  313. package/dist/server/storage/repositories/instance-relay-tunnel-repository.js.map +1 -0
  314. package/dist/server/storage/repositories/instance-tailscale-repository.js +6 -3
  315. package/dist/server/storage/repositories/instance-tailscale-repository.js.map +1 -1
  316. package/dist/server/storage/repositories/managed-skill-repository.d.ts +2 -1
  317. package/dist/server/storage/repositories/managed-skill-repository.js +14 -4
  318. package/dist/server/storage/repositories/managed-skill-repository.js.map +1 -1
  319. package/dist/server/storage/repositories/session-message-attachment-repository.d.ts +2 -0
  320. package/dist/server/storage/repositories/session-message-attachment-repository.js +24 -0
  321. package/dist/server/storage/repositories/session-message-attachment-repository.js.map +1 -1
  322. package/dist/server/storage/repositories/user-preference-profile-repository.js +6 -3
  323. package/dist/server/storage/repositories/user-preference-profile-repository.js.map +1 -1
  324. package/dist/server/storage/sqlite/client.js +534 -2
  325. package/dist/server/storage/sqlite/client.js.map +1 -1
  326. package/dist/server/storage/sqlite/schema.sql +228 -4
  327. package/dist/server/types/domain.d.ts +170 -2
  328. package/dist/server/ws/workbench-ws-hub.d.ts +14 -8
  329. package/dist/server/ws/workbench-ws-hub.js +369 -209
  330. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  331. package/dist/server/ws/ws-auth-guard.js +1 -4
  332. package/dist/server/ws/ws-auth-guard.js.map +1 -1
  333. package/dist/server/ws/ws-server.d.ts +1 -1
  334. package/dist/server/ws/ws-server.js.map +1 -1
  335. package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.d.ts +1 -0
  336. package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.js +80 -0
  337. package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.js.map +1 -0
  338. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +5 -1
  339. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +122 -4
  340. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
  341. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +17 -1
  342. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +437 -51
  343. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  344. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.d.ts +7 -1
  345. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +240 -27
  346. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -1
  347. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.d.ts +5 -1
  348. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js +108 -2
  349. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js.map +1 -1
  350. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +3 -0
  351. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +101 -8
  352. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
  353. package/node_modules/@codingns/session-sync-core/dist/providers/utils.d.ts +1 -0
  354. package/node_modules/@codingns/session-sync-core/dist/providers/utils.js +4 -1
  355. package/node_modules/@codingns/session-sync-core/dist/providers/utils.js.map +1 -1
  356. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +44 -0
  357. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
  358. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +5 -1
  359. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +153 -60
  360. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  361. package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +1 -0
  362. package/node_modules/@codingns/session-sync-core/dist/services.d.ts +1 -0
  363. package/node_modules/@codingns/session-sync-core/dist/services.js +24 -8
  364. package/node_modules/@codingns/session-sync-core/dist/services.js.map +1 -1
  365. package/node_modules/@codingns/session-sync-core/dist/types.d.ts +6 -0
  366. package/package.json +1 -1
  367. package/scripts/postinstall.mjs +0 -33
  368. package/dist/public/assets/index-BlOinYqR.js +0 -122
  369. package/dist/public/assets/index-Dg_7g6lA.css +0 -1
@@ -19,6 +19,7 @@ import { discoverWorkspaceSessionsInRuntime } from "../provider/provider-discove
19
19
  import { createTaskManager } from "../tasks/task-manager.js";
20
20
  import { HOST_TASK_TYPES } from "../tasks/task-types.js";
21
21
  import { CodexAppServerHelperClient } from "./codex-app-server-helper-client.js";
22
+ import { CodingnsProviderSessionDeleteCli } from "./provider-session-delete-cli.js";
22
23
  const RECONSTRUCTED_FORK_TARGET_PROVIDERS = new Set(["codex", "claude-code", "opencode"]);
23
24
  const FORK_RECONSTRUCTION_PAGE_SIZE = 200;
24
25
  const MAX_FORK_DEPTH = 4;
@@ -32,9 +33,13 @@ const SESSION_START_DEFERRED_PROVIDERS = new Set([
32
33
  ]);
33
34
  const MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS = 1_200;
34
35
  const WORKSPACE_DISCOVERY_BACKGROUND_MAX_AGE_MS = 15_000;
36
+ const WORKSPACE_DISCOVERY_SCAN_CONCURRENCY = 2;
35
37
  const PROVIDER_CAPABILITY_CACHE_MAX_AGE_MS = 5_000;
36
38
  const WORKSPACE_DISCOVERY_PERSIST_BATCH_SIZE = 25;
37
39
  const SESSION_TRANSACTION_HOTSPOT_THRESHOLD_MS = 150;
40
+ const WORKSPACE_STATE_REFRESH_COOLDOWN_MS = 1_500;
41
+ const SQLITE_BUSY_RETRY_LIMIT = 3;
42
+ const SQLITE_BUSY_RETRY_DELAY_MS = 100;
38
43
  export class SessionHistoryService {
39
44
  db;
40
45
  workspaceRepository;
@@ -50,6 +55,7 @@ export class SessionHistoryService {
50
55
  capabilityService;
51
56
  sessionActivityAuthorityService;
52
57
  sessionForkRepository;
58
+ providerSessionDeleteCli;
53
59
  claudeCodeHomeDir;
54
60
  codexModelOptionsService;
55
61
  openCodeModelOptionsService;
@@ -59,10 +65,12 @@ export class SessionHistoryService {
59
65
  providerSessionDiscoveryConfig;
60
66
  taskManager;
61
67
  workspaceDiscoveryStatuses = new Map();
62
- workspaceStateRefreshInflight = new Map();
68
+ workspaceStateRefreshStatuses = new Map();
63
69
  providerCapabilityCache = new Map();
64
70
  liveActivityObservationResolvers = new Set();
71
+ sessionDeletedObservers = new Set();
65
72
  workspaceSessionRelations = new Map();
73
+ workspaceStateRefreshTaskSequence = 0;
66
74
  constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}, taskManager = createTaskManager()) {
67
75
  this.db = db;
68
76
  this.workspaceRepository = workspaceRepository;
@@ -75,6 +83,8 @@ export class SessionHistoryService {
75
83
  this.sessionMessageOriginRepository = sessionMessageOriginRepository;
76
84
  this.sessionActivityAuthorityService = sessionActivityAuthorityService;
77
85
  this.sessionForkRepository = sessionForkRepository ?? new SessionForkRepository(db);
86
+ this.providerSessionDeleteCli =
87
+ adapterOverrides.providerSessionDeleteCli ?? new CodingnsProviderSessionDeleteCli(config);
78
88
  this.taskManager = taskManager;
79
89
  this.claudeCodeHomeDir = config.claudeCodeHomeDir;
80
90
  this.providerCliCommandPaths = {
@@ -102,7 +112,8 @@ export class SessionHistoryService {
102
112
  new CodexAdapter({
103
113
  homeDir: config.codexHomeDir,
104
114
  forkTransportFactory: adapterOverrides.codexForkTransportFactory
105
- ?? createCodexForkTransportFactory(config.codexCliPath, config.codexHomeDir)
115
+ ?? createCodexForkTransportFactory(config.codexCliPath, config.codexHomeDir),
116
+ threadControlTransportFactory: createCodexThreadControlTransportFactory(config.codexCliPath, config.codexHomeDir)
106
117
  }),
107
118
  new GeminiAdapter({
108
119
  homeDir: config.geminiHomeDir,
@@ -147,6 +158,14 @@ export class SessionHistoryService {
147
158
  }
148
159
  };
149
160
  }
161
+ registerSessionDeletedObserver(observer) {
162
+ this.sessionDeletedObservers.add(observer);
163
+ return {
164
+ close: () => {
165
+ this.sessionDeletedObservers.delete(observer);
166
+ }
167
+ };
168
+ }
150
169
  registerBackgroundTasks() {
151
170
  if (!this.taskManager.has(HOST_TASK_TYPES.workspaceDiscovery)) {
152
171
  this.taskManager.register({
@@ -159,6 +178,7 @@ export class SessionHistoryService {
159
178
  this.taskManager.register({
160
179
  taskType: HOST_TASK_TYPES.workspaceDiscoveryScan,
161
180
  executionLane: "helper_process",
181
+ concurrency: WORKSPACE_DISCOVERY_SCAN_CONCURRENCY,
162
182
  helperProcessHandler: "session.workspace_discovery",
163
183
  run: async ({ config, workspacePath, knownSessions }, context) => await discoverWorkspaceSessionsInRuntime(config, workspacePath, knownSessions, context.signal)
164
184
  });
@@ -319,6 +339,12 @@ export class SessionHistoryService {
319
339
  originRef: null
320
340
  };
321
341
  }
342
+ resolveMessageOriginByClientRequestId(sessionId, clientRequestId, messageId, updatedAt) {
343
+ if (!this.sessionMessageOriginRepository || !clientRequestId || !messageId) {
344
+ return;
345
+ }
346
+ this.sessionMessageOriginRepository.resolveMessageId(sessionId, clientRequestId, messageId, updatedAt);
347
+ }
322
348
  async findLatestUserMessage(sessionId, content, maxAttempts = 12, minTimestamp = null) {
323
349
  const binding = this.getBindingOrThrow(sessionId);
324
350
  const acceptedContents = new Set((Array.isArray(content) ? content : [content]).filter((value) => value.trim().length > 0));
@@ -1066,6 +1092,44 @@ export class SessionHistoryService {
1066
1092
  isArchived: nextArchivedState
1067
1093
  });
1068
1094
  }
1095
+ async deleteSession(sessionId, userId) {
1096
+ const binding = this.getBindingOrThrow(sessionId);
1097
+ const existing = this.getSessionListItemOrThrow(sessionId, userId);
1098
+ if (existing.runningState === "starting" || existing.runningState === "running") {
1099
+ throw new AppError({
1100
+ statusCode: 409,
1101
+ errorCode: "SESSION_DELETE_RUNNING",
1102
+ detail: "运行中的会话不能直接删除,请先等当前执行结束",
1103
+ field: "sessionId"
1104
+ });
1105
+ }
1106
+ try {
1107
+ await this.providerSessionDeleteCli.deleteSession({
1108
+ provider: binding.provider,
1109
+ providerSessionId: binding.providerSessionId,
1110
+ rawStoreRef: binding.rawStoreRef
1111
+ });
1112
+ }
1113
+ catch (error) {
1114
+ if (!isProviderSessionMissing(error)) {
1115
+ throw mapSessionProviderError(error);
1116
+ }
1117
+ }
1118
+ for (const observer of this.sessionDeletedObservers) {
1119
+ await observer({
1120
+ sessionId,
1121
+ userId,
1122
+ workspaceId: binding.workspaceId,
1123
+ remainingWorkspaceSessionCount: this.countOtherWorkspaceSessions(binding.workspaceId, sessionId)
1124
+ });
1125
+ }
1126
+ const deleteTransaction = this.db.transaction((targetSessionId) => {
1127
+ this.detachSessionRelationsBeforeDelete(targetSessionId);
1128
+ this.deleteSessionById(targetSessionId);
1129
+ });
1130
+ deleteTransaction(sessionId);
1131
+ this.removeWorkspaceSessionRelation(sessionId);
1132
+ }
1069
1133
  async renameSessionTitle(sessionId, userId, title) {
1070
1134
  const binding = this.getBindingOrThrow(sessionId);
1071
1135
  const existing = this.getSessionListItemOrThrow(sessionId, userId);
@@ -1215,7 +1279,7 @@ export class SessionHistoryService {
1215
1279
  const existingIndex = existing
1216
1280
  ? this.sessionIndexRepository.findIndexRecordBySessionId(existing.sessionId)
1217
1281
  : null;
1218
- this.sessionBindingRepository.upsert({
1282
+ const nextBinding = {
1219
1283
  sessionId,
1220
1284
  workspaceId: workspace.id,
1221
1285
  provider: session.provider,
@@ -1223,7 +1287,10 @@ export class SessionHistoryService {
1223
1287
  rawStoreRef: session.rawStoreRef,
1224
1288
  createdAt,
1225
1289
  updatedAt: timestamp
1226
- });
1290
+ };
1291
+ if (!areEquivalentSessionBindings(existing, nextBinding)) {
1292
+ this.sessionBindingRepository.upsert(nextBinding);
1293
+ }
1227
1294
  const preservedParentSessionId = existingIndex?.parentSessionId
1228
1295
  ?? this.sessionForkRepository.findBySessionId(sessionId)?.parentSessionId
1229
1296
  ?? null;
@@ -1231,7 +1298,7 @@ export class SessionHistoryService {
1231
1298
  ? this.sessionIndexRepository.findIndexRecordBySessionId(preservedParentSessionId)?.title ?? null
1232
1299
  : null;
1233
1300
  const preservedTitle = resolvePersistedSessionTitle(session.provider, session.title, existingIndex?.title ?? null, preservedParentTitle);
1234
- this.sessionIndexRepository.upsert({
1301
+ const nextIndex = {
1235
1302
  sessionId,
1236
1303
  workspaceId: workspace.id,
1237
1304
  provider: session.provider,
@@ -1243,12 +1310,15 @@ export class SessionHistoryService {
1243
1310
  subagentLabel: existingIndex?.subagentLabel ?? null,
1244
1311
  title: preservedTitle,
1245
1312
  messageCount: session.messageCount,
1246
- isArchived: resolveDiscoveredArchiveState(existingIndex?.isArchived ?? false, session.isArchived),
1313
+ isArchived: resolveDiscoveredArchiveState(session.provider, existingIndex?.isArchived ?? false, session.isArchived),
1247
1314
  lastMessageAt: session.lastMessageAt,
1248
1315
  createdAt,
1249
1316
  updatedAt: timestamp
1250
- });
1251
- this.sessionStatusSnapshotRepository.upsert({
1317
+ };
1318
+ if (!areEquivalentSessionIndexRecords(existingIndex, nextIndex)) {
1319
+ this.sessionIndexRepository.upsert(nextIndex);
1320
+ }
1321
+ const nextSnapshot = {
1252
1322
  sessionId,
1253
1323
  syncStatus: currentSnapshot?.syncStatus ?? "idle",
1254
1324
  syncCursor: currentSnapshot?.syncCursor ?? null,
@@ -1257,13 +1327,17 @@ export class SessionHistoryService {
1257
1327
  lastErrorDetail: currentSnapshot?.lastErrorDetail ?? null,
1258
1328
  resumedAt: currentSnapshot?.resumedAt ?? null,
1259
1329
  updatedAt: timestamp
1260
- });
1330
+ };
1331
+ if (!areEquivalentSessionStatusSnapshots(currentSnapshot, nextSnapshot)) {
1332
+ this.sessionStatusSnapshotRepository.upsert(nextSnapshot);
1333
+ }
1261
1334
  discoveredSessionIds.set(buildProviderSessionKey(session.provider, session.providerSessionId), sessionId);
1262
1335
  persistedSessions.push({
1263
1336
  session,
1264
1337
  sessionId,
1265
1338
  createdAt,
1266
- existingIndex
1339
+ existingIndex,
1340
+ pass1Index: nextIndex
1267
1341
  });
1268
1342
  }
1269
1343
  });
@@ -1293,7 +1367,7 @@ export class SessionHistoryService {
1293
1367
  const resolvedParentTitle = resolvedParentSessionId
1294
1368
  ? this.sessionIndexRepository.findIndexRecordBySessionId(resolvedParentSessionId)?.title ?? null
1295
1369
  : null;
1296
- this.sessionIndexRepository.upsert({
1370
+ const nextIndex = {
1297
1371
  sessionId: persistedSession.sessionId,
1298
1372
  workspaceId: workspace.id,
1299
1373
  provider: persistedSession.session.provider,
@@ -1315,11 +1389,14 @@ export class SessionHistoryService {
1315
1389
  ?? null,
1316
1390
  title: resolvePersistedSessionTitle(persistedSession.session.provider, persistedSession.session.title, persistedSession.existingIndex?.title ?? null, resolvedParentTitle),
1317
1391
  messageCount: persistedSession.session.messageCount,
1318
- isArchived: resolveDiscoveredArchiveState(persistedSession.existingIndex?.isArchived ?? false, persistedSession.session.isArchived),
1392
+ isArchived: resolveDiscoveredArchiveState(persistedSession.session.provider, persistedSession.existingIndex?.isArchived ?? false, persistedSession.session.isArchived),
1319
1393
  lastMessageAt: persistedSession.session.lastMessageAt,
1320
1394
  createdAt: persistedSession.createdAt,
1321
1395
  updatedAt: timestamp
1322
- });
1396
+ };
1397
+ if (!areEquivalentSessionIndexRecords(persistedSession.pass1Index, nextIndex)) {
1398
+ this.sessionIndexRepository.upsert(nextIndex);
1399
+ }
1323
1400
  }
1324
1401
  });
1325
1402
  const persistPass2StartedAt = Date.now();
@@ -1387,7 +1464,22 @@ export class SessionHistoryService {
1387
1464
  discoveredSessions: sessions.length,
1388
1465
  returnedSessions: nextItems.length,
1389
1466
  discoveryComplete: discovery.isComplete,
1390
- providerDiagnostics: (discovery.providerDiagnostics ?? []).map((entry) => `${entry.provider}:${entry.status}:${Math.round(entry.durationMs)}ms`),
1467
+ providerDiagnostics: (discovery.providerDiagnostics ?? []).map((entry) => {
1468
+ const scannedFiles = entry.scannedFiles ?? 0;
1469
+ const skippedByMtimeSize = entry.skippedByMtimeSize ?? 0;
1470
+ const parsedFiles = entry.parsedFiles ?? 0;
1471
+ const bytesRead = entry.bytesRead ?? 0;
1472
+ return [
1473
+ entry.provider,
1474
+ entry.status,
1475
+ `${Math.round(entry.durationMs)}ms`,
1476
+ `sessions=${entry.sessionCount}`,
1477
+ `scanned=${scannedFiles}`,
1478
+ `skipped=${skippedByMtimeSize}`,
1479
+ `parsed=${parsedFiles}`,
1480
+ `bytes=${bytesRead}`
1481
+ ].join(":");
1482
+ }),
1391
1483
  refreshedStates: refreshCandidates.length,
1392
1484
  discoverMs: discoverDurationMs,
1393
1485
  persistMs: persistDurationMs,
@@ -1542,13 +1634,6 @@ export class SessionHistoryService {
1542
1634
  const originByMessageId = new Map(originRows
1543
1635
  .filter((row) => row.messageId)
1544
1636
  .map((row) => [row.messageId, row]));
1545
- const unresolvedRows = originRepository.listUnresolvedBySessionAndContents(sessionId, [...new Set(messages.map((message) => message.content).filter((content) => content.trim().length > 0))]);
1546
- const unresolvedByContent = new Map();
1547
- for (const row of unresolvedRows) {
1548
- const current = unresolvedByContent.get(row.content) ?? [];
1549
- current.push(row);
1550
- unresolvedByContent.set(row.content, current);
1551
- }
1552
1637
  return messages.map((message) => {
1553
1638
  const resolved = originByMessageId.get(message.messageId) ?? null;
1554
1639
  if (resolved) {
@@ -1565,21 +1650,10 @@ export class SessionHistoryService {
1565
1650
  originRef: null
1566
1651
  };
1567
1652
  }
1568
- const candidates = unresolvedByContent.get(message.content) ?? [];
1569
- const matched = candidates.find((row) => isMessageAtOrAfter(message.timestamp, row.createdAt)) ?? null;
1570
- if (!matched) {
1571
- return {
1572
- ...message,
1573
- origin: null,
1574
- originRef: null
1575
- };
1576
- }
1577
- originRepository.resolveMessageId(sessionId, matched.clientRequestId, message.messageId, message.timestamp);
1578
- unresolvedByContent.set(message.content, candidates.filter((candidate) => candidate.clientRequestId !== matched.clientRequestId));
1579
1653
  return {
1580
1654
  ...message,
1581
- origin: matched.origin,
1582
- originRef: matched.originRef
1655
+ origin: null,
1656
+ originRef: null
1583
1657
  };
1584
1658
  });
1585
1659
  }
@@ -1718,6 +1792,9 @@ export class SessionHistoryService {
1718
1792
  if (shouldSkipClaudePendingBinding(binding)) {
1719
1793
  return;
1720
1794
  }
1795
+ if (!shouldSyncSessionTitleFromProvider(binding.provider, currentIndex.title)) {
1796
+ return;
1797
+ }
1721
1798
  const nextTitle = (await this.providerDiscoveryHelperClient.readSessionTitle({
1722
1799
  config: this.providerSessionDiscoveryConfig,
1723
1800
  provider: binding.provider,
@@ -1926,13 +2003,71 @@ export class SessionHistoryService {
1926
2003
  return;
1927
2004
  }
1928
2005
  const inflightKey = `${workspaceId}:${userId}`;
1929
- if (this.workspaceStateRefreshInflight.has(inflightKey)) {
2006
+ const refreshState = this.getOrCreateWorkspaceStateRefreshStatus(inflightKey);
2007
+ const now = Date.now();
2008
+ refreshState.lastRequestedAt = now;
2009
+ refreshState.phase = refreshState.phase === "fresh" ? "stale" : refreshState.phase;
2010
+ refreshState.dirtyReasons.add("workspace.discovery.deferred_state_refresh");
2011
+ mergeWorkspaceStateRefreshSessions(refreshState.pendingSessions, sessions);
2012
+ if (refreshState.phase === "running" && refreshState.runningPromise) {
1930
2013
  return;
1931
2014
  }
2015
+ if (this.isWorkspaceStateRefreshCoolingDown(refreshState, now)) {
2016
+ refreshState.phase = "stale";
2017
+ this.ensureWorkspaceStateRefreshCooldownTimer(inflightKey, workspaceId, userId, refreshState);
2018
+ return;
2019
+ }
2020
+ this.startWorkspaceStateRefreshTask(inflightKey, workspaceId, userId, refreshState);
2021
+ }
2022
+ getOrCreateWorkspaceStateRefreshStatus(key) {
2023
+ const existing = this.workspaceStateRefreshStatuses.get(key);
2024
+ if (existing) {
2025
+ return existing;
2026
+ }
2027
+ const created = {
2028
+ phase: "fresh",
2029
+ dirtyReasons: new Set(),
2030
+ pendingSessions: new Map(),
2031
+ runningPromise: null,
2032
+ cooldownTimer: null,
2033
+ lastRequestedAt: null,
2034
+ lastStartedAt: null,
2035
+ lastCompletedAt: null,
2036
+ lastFailedAt: null,
2037
+ nextAllowedAt: null,
2038
+ runningTaskId: null
2039
+ };
2040
+ this.workspaceStateRefreshStatuses.set(key, created);
2041
+ return created;
2042
+ }
2043
+ isWorkspaceStateRefreshCoolingDown(state, now) {
2044
+ if (state.nextAllowedAt === null || now >= state.nextAllowedAt) {
2045
+ return false;
2046
+ }
2047
+ return state.phase === "cooldown" || state.phase === "failed";
2048
+ }
2049
+ startWorkspaceStateRefreshTask(key, workspaceId, userId, state) {
2050
+ if (state.runningPromise) {
2051
+ return;
2052
+ }
2053
+ const sessions = [...state.pendingSessions.values()];
2054
+ if (sessions.length === 0) {
2055
+ state.phase = "fresh";
2056
+ state.dirtyReasons.clear();
2057
+ return;
2058
+ }
2059
+ state.pendingSessions.clear();
2060
+ state.phase = "running";
2061
+ state.lastStartedAt = Date.now();
2062
+ state.runningTaskId = `${key}:${++this.workspaceStateRefreshTaskSequence}`;
1932
2063
  const startedAt = Date.now();
1933
2064
  const task = delay(0)
1934
2065
  .then(() => this.refreshRecentSessionStates(sessions, userId))
1935
2066
  .then(() => {
2067
+ state.lastCompletedAt = Date.now();
2068
+ state.phase = "cooldown";
2069
+ state.nextAllowedAt = state.lastCompletedAt + WORKSPACE_STATE_REFRESH_COOLDOWN_MS;
2070
+ state.dirtyReasons.clear();
1936
2071
  logPerformance("workspace.refresh_recent_session_states", Date.now() - startedAt, {
1937
2072
  workspaceId,
1938
2073
  refreshedStates: sessions.length
@@ -1941,6 +2076,9 @@ export class SessionHistoryService {
1941
2076
  });
1942
2077
  })
1943
2078
  .catch((error) => {
2079
+ state.lastFailedAt = Date.now();
2080
+ state.phase = "failed";
2081
+ state.nextAllowedAt = state.lastFailedAt + WORKSPACE_STATE_REFRESH_COOLDOWN_MS;
1944
2082
  logPerformance("workspace.refresh_recent_session_states.failed", Date.now() - startedAt, {
1945
2083
  workspaceId,
1946
2084
  refreshedStates: sessions.length,
@@ -1951,9 +2089,42 @@ export class SessionHistoryService {
1951
2089
  });
1952
2090
  })
1953
2091
  .finally(() => {
1954
- this.workspaceStateRefreshInflight.delete(inflightKey);
2092
+ state.runningPromise = null;
2093
+ state.runningTaskId = null;
2094
+ if (state.pendingSessions.size === 0) {
2095
+ if (state.phase === "cooldown") {
2096
+ this.ensureWorkspaceStateRefreshCooldownTimer(key, workspaceId, userId, state);
2097
+ return;
2098
+ }
2099
+ if (state.phase === "failed") {
2100
+ this.ensureWorkspaceStateRefreshCooldownTimer(key, workspaceId, userId, state);
2101
+ return;
2102
+ }
2103
+ state.phase = "fresh";
2104
+ return;
2105
+ }
2106
+ state.phase = "stale";
2107
+ this.ensureWorkspaceStateRefreshCooldownTimer(key, workspaceId, userId, state);
1955
2108
  });
1956
- this.workspaceStateRefreshInflight.set(inflightKey, task);
2109
+ state.runningPromise = task;
2110
+ }
2111
+ ensureWorkspaceStateRefreshCooldownTimer(key, workspaceId, userId, state) {
2112
+ if (state.cooldownTimer) {
2113
+ return;
2114
+ }
2115
+ const now = Date.now();
2116
+ const delayMs = Math.max(0, (state.nextAllowedAt ?? now) - now);
2117
+ state.cooldownTimer = setTimeout(() => {
2118
+ state.cooldownTimer = null;
2119
+ if (state.pendingSessions.size === 0) {
2120
+ state.phase = "fresh";
2121
+ state.dirtyReasons.clear();
2122
+ state.nextAllowedAt = null;
2123
+ return;
2124
+ }
2125
+ state.phase = "stale";
2126
+ this.startWorkspaceStateRefreshTask(key, workspaceId, userId, state);
2127
+ }, delayMs);
1957
2128
  }
1958
2129
  async cleanupStaleHiddenSessions(workspaceId, userId, sessions) {
1959
2130
  const discoveredProviderSessionIds = new Set(sessions.map((session) => buildProviderSessionKey(session.provider, session.providerSessionId)));
@@ -1981,6 +2152,7 @@ export class SessionHistoryService {
1981
2152
  }
1982
2153
  const deleteTransaction = this.db.transaction((ids) => {
1983
2154
  for (const sessionId of ids) {
2155
+ this.detachSessionRelationsBeforeDelete(sessionId);
1984
2156
  this.deleteSessionById(sessionId);
1985
2157
  }
1986
2158
  });
@@ -2250,10 +2422,14 @@ export class SessionHistoryService {
2250
2422
  }
2251
2423
  }
2252
2424
  deleteSessionById(sessionId) {
2425
+ this.sessionMessageAttachmentService.deleteSessionAttachments(sessionId);
2253
2426
  this.sessionChangedFileService.deleteBySessionId(sessionId);
2254
2427
  this.db
2255
2428
  .prepare("DELETE FROM session_message_attachments WHERE session_id = ?")
2256
2429
  .run(sessionId);
2430
+ this.db
2431
+ .prepare("DELETE FROM session_message_origins WHERE session_id = ?")
2432
+ .run(sessionId);
2257
2433
  this.db
2258
2434
  .prepare("DELETE FROM session_send_queue WHERE session_id = ?")
2259
2435
  .run(sessionId);
@@ -2276,6 +2452,82 @@ export class SessionHistoryService {
2276
2452
  .prepare("DELETE FROM session_bindings WHERE session_id = ?")
2277
2453
  .run(sessionId);
2278
2454
  }
2455
+ countOtherWorkspaceSessions(workspaceId, sessionId) {
2456
+ const row = this.db
2457
+ .prepare(`SELECT COUNT(*) AS count
2458
+ FROM session_bindings
2459
+ WHERE workspace_id = ?
2460
+ AND session_id != ?`)
2461
+ .get(workspaceId, sessionId);
2462
+ return Number(row?.count ?? 0);
2463
+ }
2464
+ detachSessionRelationsBeforeDelete(sessionId) {
2465
+ this.db
2466
+ .prepare(`UPDATE session_indices
2467
+ SET parent_session_id = NULL
2468
+ WHERE parent_session_id = ?`)
2469
+ .run(sessionId);
2470
+ this.db
2471
+ .prepare(`DELETE FROM session_forks
2472
+ WHERE parent_session_id = ?
2473
+ OR fork_source_session_id = ?`)
2474
+ .run(sessionId, sessionId);
2475
+ this.db
2476
+ .prepare("DELETE FROM butler_control_sessions WHERE session_id = ?")
2477
+ .run(sessionId);
2478
+ const butlerSessionIds = this.db
2479
+ .prepare(`SELECT id
2480
+ FROM butler_sessions
2481
+ WHERE session_id = ?`)
2482
+ .all(sessionId)
2483
+ .map((row) => String(row.id));
2484
+ if (butlerSessionIds.length === 0) {
2485
+ return;
2486
+ }
2487
+ const butlerPlaceholders = butlerSessionIds.map(() => "?").join(", ");
2488
+ const checkpointIds = this.db
2489
+ .prepare(`SELECT id
2490
+ FROM session_checkpoints
2491
+ WHERE butler_session_id IN (${butlerPlaceholders})`)
2492
+ .all(...butlerSessionIds)
2493
+ .map((row) => String(row.id));
2494
+ if (checkpointIds.length > 0) {
2495
+ const checkpointPlaceholders = checkpointIds.map(() => "?").join(", ");
2496
+ this.db
2497
+ .prepare(`UPDATE project_memories
2498
+ SET source_checkpoint_id = NULL
2499
+ WHERE source_checkpoint_id IN (${checkpointPlaceholders})`)
2500
+ .run(...checkpointIds);
2501
+ }
2502
+ this.db
2503
+ .prepare(`UPDATE project_memories
2504
+ SET source_butler_session_id = NULL
2505
+ WHERE source_butler_session_id IN (${butlerPlaceholders})`)
2506
+ .run(...butlerSessionIds);
2507
+ this.db
2508
+ .prepare(`UPDATE patrol_runs
2509
+ SET butler_session_id = NULL
2510
+ WHERE butler_session_id IN (${butlerPlaceholders})`)
2511
+ .run(...butlerSessionIds);
2512
+ this.db
2513
+ .prepare(`UPDATE verification_runs
2514
+ SET butler_session_id = NULL
2515
+ WHERE butler_session_id IN (${butlerPlaceholders})`)
2516
+ .run(...butlerSessionIds);
2517
+ this.db
2518
+ .prepare("DELETE FROM butler_sessions WHERE session_id = ?")
2519
+ .run(sessionId);
2520
+ }
2521
+ removeWorkspaceSessionRelation(sessionId) {
2522
+ for (const relationMap of this.workspaceSessionRelations.values()) {
2523
+ relationMap.delete(sessionId);
2524
+ for (const relation of relationMap.values()) {
2525
+ if (relation.parentSessionId === sessionId) {
2526
+ relation.parentSessionId = null;
2527
+ }
2528
+ }
2529
+ }
2530
+ }
2279
2531
  buildKnownSessionSummaries(sessions, workspacePath) {
2280
2532
  return sessions
2281
2533
  .filter((session) => !this.isPendingSessionAlias(session))
@@ -2451,6 +2703,19 @@ function createCodexForkTransportFactory(commandPath, homeDir) {
2451
2703
  };
2452
2704
  };
2453
2705
  }
2706
+ function createCodexThreadControlTransportFactory(commandPath, homeDir) {
2707
+ return () => {
2708
+ const client = new CodexAppServerHelperClient(commandPath, { homeDir });
2709
+ const transport = client.createThreadControlTransport();
2710
+ return {
2711
+ ...transport,
2712
+ close() {
2713
+ transport.close();
2714
+ client.dispose();
2715
+ }
2716
+ };
2717
+ };
2718
+ }
2454
2719
  function buildInspectionActivityObservation(sessionId, inspection, observedAt) {
2455
2720
  const resolvedRunningState = inspection.runningState === "failed"
2456
2721
  ? "failed"
@@ -2532,6 +2797,11 @@ function buildSessionStateRefreshCandidates(items, recentCount) {
2532
2797
  }
2533
2798
  return Array.from(deduped.values());
2534
2799
  }
2800
+ function mergeWorkspaceStateRefreshSessions(target, sessions) {
2801
+ for (const session of sessions) {
2802
+ target.set(session.sessionId, session);
2803
+ }
2804
+ }
2535
2805
  function isSessionStateRefreshCandidate(item) {
2536
2806
  return item.activityState === "running"
2537
2807
  || item.runningState === "starting"
@@ -2609,12 +2879,20 @@ function mergeSessionIndexRecord(input) {
2609
2879
  subagentLabel: input.target?.subagentLabel ?? input.source?.subagentLabel ?? null,
2610
2880
  title: pickPreferredSessionTitle(input.target?.title ?? null, input.source?.title ?? null),
2611
2881
  messageCount: Math.max(input.target?.messageCount ?? 0, input.source?.messageCount ?? 0),
2612
- isArchived: Boolean(input.target?.isArchived || input.source?.isArchived),
2882
+ isArchived: mergePersistedArchiveState(input.provider, input.target?.isArchived, input.source?.isArchived),
2613
2883
  lastMessageAt: pickLaterIso(input.target?.lastMessageAt ?? null, input.source?.lastMessageAt ?? null),
2614
2884
  createdAt: pickEarlierIso(input.target?.createdAt ?? null, input.source?.createdAt ?? null) ?? input.timestamp,
2615
2885
  updatedAt: input.timestamp
2616
2886
  };
2617
2887
  }
2888
+ function mergePersistedArchiveState(provider, targetArchived, sourceArchived) {
2889
+ // 只有 Codex 这类真实支持归档的 provider 才认底层归档真相;
2890
+ // 其他 provider 的归档完全由 Host 本地索引维护,不能让旧副本把恢复状态再刷回去。
2891
+ if (shouldUseProviderDiscoveredArchiveState(provider)) {
2892
+ return Boolean(targetArchived || sourceArchived);
2893
+ }
2894
+ return targetArchived ?? sourceArchived ?? false;
2895
+ }
2618
2896
  function mergeSessionStatusSnapshot(input) {
2619
2897
  if (!input.target && !input.source) {
2620
2898
  return null;
@@ -2915,12 +3193,16 @@ function isCloseClaudeSessionTimestamp(left, right, maxGapMs = 2 * 60 * 1000) {
2915
3193
  }
2916
3194
  return Math.abs(leftAt - rightAt) <= maxGapMs;
2917
3195
  }
2918
- function resolveDiscoveredArchiveState(existingArchived, discoveredArchived) {
2919
- if (existingArchived) {
2920
- return true;
3196
+ function resolveDiscoveredArchiveState(provider, existingArchived, discoveredArchived) {
3197
+ if (!shouldUseProviderDiscoveredArchiveState(provider)) {
3198
+ return existingArchived;
2921
3199
  }
2922
3200
  return discoveredArchived === true;
2923
3201
  }
3202
+ function shouldUseProviderDiscoveredArchiveState(provider) {
3203
+ // 当前只有 Codex 的归档能稳定映射到底层文件位置;其余 provider 一律信本地 session_indices。
3204
+ return provider === "codex";
3205
+ }
2924
3206
  function isMessageAtOrAfter(timestamp, minTimestamp) {
2925
3207
  if (!minTimestamp) {
2926
3208
  return true;
@@ -2942,6 +3224,9 @@ function isAcceptedUserMessageTimestamp(provider, timestamp, minTimestamp) {
2942
3224
  function isSyntheticKimiHistoryTimestamp(timestamp) {
2943
3225
  return timestamp.startsWith("2020-01-01T00:");
2944
3226
  }
3227
+ function isProviderSessionMissing(error) {
3228
+ return error instanceof Error && error.message === "PROVIDER_SESSION_NOT_FOUND";
3229
+ }
2945
3230
  function createDeliveredHistoryMessageState() {
2946
3231
  return {
2947
3232
  signaturesByMessageId: new Map(),
@@ -3153,6 +3438,16 @@ function isSyntheticCodexSessionTitle(title) {
3153
3438
  return (/^rollout-\d{4}-\d{2}-\d{2}t/i.test(title) ||
3154
3439
  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(title));
3155
3440
  }
3441
+ function shouldSyncSessionTitleFromProvider(provider, currentTitle) {
3442
+ const normalizedTitle = currentTitle?.trim() ?? "";
3443
+ if (normalizedTitle.length === 0) {
3444
+ return true;
3445
+ }
3446
+ if (provider === "codex" && isSyntheticCodexSessionTitle(normalizedTitle)) {
3447
+ return true;
3448
+ }
3449
+ return false;
3450
+ }
3156
3451
  function shouldRemoveHiddenClaudeDebugSession(session) {
3157
3452
  const normalizedRawStoreRef = session.rawStoreRef.replaceAll("\\", "/");
3158
3453
  if (normalizedRawStoreRef.includes("/subagents/")) {
@@ -3325,6 +3620,56 @@ function getAbortMessage(reason) {
3325
3620
  }
3326
3621
  return "任务已取消";
3327
3622
  }
3623
+ function areEquivalentSessionBindings(current, next) {
3624
+ if (!current) {
3625
+ return false;
3626
+ }
3627
+ return (current.sessionId === next.sessionId &&
3628
+ current.workspaceId === next.workspaceId &&
3629
+ current.provider === next.provider &&
3630
+ current.providerSessionId === next.providerSessionId &&
3631
+ current.rawStoreRef === next.rawStoreRef &&
3632
+ current.createdAt === next.createdAt);
3633
+ }
3634
+ function areEquivalentSessionIndexRecords(current, next) {
3635
+ if (!current) {
3636
+ return false;
3637
+ }
3638
+ return (current.sessionId === next.sessionId &&
3639
+ current.workspaceId === next.workspaceId &&
3640
+ current.provider === next.provider &&
3641
+ (current.parentSessionId ?? null) === (next.parentSessionId ?? null) &&
3642
+ (current.sessionKind ?? "default") === (next.sessionKind ?? "default") &&
3643
+ (current.annotationSourceMessageId ?? null) === (next.annotationSourceMessageId ?? null) &&
3644
+ (current.annotationSourceText ?? null) === (next.annotationSourceText ?? null) &&
3645
+ (current.isSubagent ?? false) === (next.isSubagent ?? false) &&
3646
+ (current.subagentLabel ?? null) === (next.subagentLabel ?? null) &&
3647
+ current.title === next.title &&
3648
+ current.messageCount === next.messageCount &&
3649
+ current.isArchived === next.isArchived &&
3650
+ (current.lastMessageAt ?? null) === (next.lastMessageAt ?? null) &&
3651
+ current.createdAt === next.createdAt);
3652
+ }
3653
+ function areEquivalentSessionStatusSnapshots(current, next) {
3654
+ if (!current) {
3655
+ return false;
3656
+ }
3657
+ return (current.sessionId === next.sessionId &&
3658
+ current.syncStatus === next.syncStatus &&
3659
+ (current.syncCursor ?? null) === (next.syncCursor ?? null) &&
3660
+ (current.lastSyncAt ?? null) === (next.lastSyncAt ?? null) &&
3661
+ (current.lastErrorCode ?? null) === (next.lastErrorCode ?? null) &&
3662
+ (current.lastErrorDetail ?? null) === (next.lastErrorDetail ?? null) &&
3663
+ (current.resumedAt ?? null) === (next.resumedAt ?? null));
3664
+ }
3665
+ function isSqliteBusyError(error) {
3666
+ if (!error || typeof error !== "object") {
3667
+ return false;
3668
+ }
3669
+ const sqliteCode = "code" in error ? error.code : null;
3670
+ const message = error instanceof Error ? error.message : String(error);
3671
+ return sqliteCode === "SQLITE_BUSY" || message.includes("database is locked");
3672
+ }
3328
3673
  async function runBatchedTransactions(items, batchSize, transaction, logOptions) {
3329
3674
  const normalizedBatchSize = Math.max(1, Math.floor(batchSize) || 1);
3330
3675
  let batchCount = 0;
@@ -3332,7 +3677,20 @@ async function runBatchedTransactions(items, batchSize, transaction, logOptions)
3332
3677
  for (let index = 0; index < items.length; index += normalizedBatchSize) {
3333
3678
  const batch = items.slice(index, index + normalizedBatchSize);
3334
3679
  const batchStartedAt = Date.now();
3335
- transaction(batch);
3680
+ let retryCount = 0;
3681
+ while (true) {
3682
+ try {
3683
+ transaction(batch);
3684
+ break;
3685
+ }
3686
+ catch (error) {
3687
+ if (!isSqliteBusyError(error) || retryCount >= SQLITE_BUSY_RETRY_LIMIT) {
3688
+ throw error;
3689
+ }
3690
+ retryCount += 1;
3691
+ await delay(SQLITE_BUSY_RETRY_DELAY_MS * retryCount);
3692
+ }
3693
+ }
3336
3694
  const batchDurationMs = Date.now() - batchStartedAt;
3337
3695
  const nextBatchIndex = batchCount + 1;
3338
3696
  if (logOptions) {
@@ -3341,6 +3699,7 @@ async function runBatchedTransactions(items, batchSize, transaction, logOptions)
3341
3699
  batchIndex: nextBatchIndex,
3342
3700
  batchSize: batch.length,
3343
3701
  batchStartIndex: index,
3702
+ retryCount,
3344
3703
  totalItems: items.length,
3345
3704
  configuredBatchSize: normalizedBatchSize
3346
3705
  }, {