@jingyi0605/codingns 0.8.5 → 0.9.5

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 (515) hide show
  1. package/bin/codingns.mjs +7 -156
  2. package/dist/public/assets/AdaptiveButlerPage-kkJDsnCO.js +2 -0
  3. package/dist/public/assets/{App-BOHBGFOd.js → App-DrNI9lWA.js} +6 -6
  4. package/dist/public/assets/{BootstrapPage-BxHQT4nA.js → BootstrapPage-QgVH5Mps.js} +1 -1
  5. package/dist/public/assets/{ConversationPage-DWFsF6BB.js → ConversationPage-DVk8VfIj.js} +6 -6
  6. package/dist/public/assets/{DesktopDetachPreviewPage-DOgEjYEf.js → DesktopDetachPreviewPage-BhfP0TpH.js} +1 -1
  7. package/dist/public/assets/DesktopModal-DRmDrv0S.js +1 -0
  8. package/dist/public/assets/DesktopWindowPage-DNbJXnSs.js +2 -0
  9. package/dist/public/assets/FileContextPanel---fLO4ve.js +1 -0
  10. package/dist/public/assets/GitSidebar-sXUE0TqT.js +6 -0
  11. package/dist/public/assets/MobileCreateSessionSheet-BftZ5pvb.js +1 -0
  12. package/dist/public/assets/MobileSheet-nw5SCa3N.js +1 -0
  13. package/dist/public/assets/{MobileTopHeaderFrame-lcp2GscV.js → MobileTopHeaderFrame-DH_D02Wy.js} +1 -1
  14. package/dist/public/assets/MobileWorkspaceSwitcherHeader-2K406G5p.js +1 -0
  15. package/dist/public/assets/{PluginAccessOverview-DGcKAMQl.js → PluginAccessOverview-BVJihw3D.js} +1 -1
  16. package/dist/public/assets/PluginContainerPage-CR4vStvr.js +1 -0
  17. package/dist/public/assets/{PluginDetailPage-CAJ7LFpD.js → PluginDetailPage-CrMX0Mnm.js} +1 -1
  18. package/dist/public/assets/{PluginsListPage-BxZG1NyT.js → PluginsListPage-FtIL71Yg.js} +1 -1
  19. package/dist/public/assets/{RelayConnectEntryPage-CfNO_TIl.js → RelayConnectEntryPage-Bt1apX53.js} +1 -1
  20. package/dist/public/assets/{ServerSettingsModal-by36Z_5k.js → ServerSettingsModal-D-guzPrI.js} +1 -1
  21. package/dist/public/assets/SessionIndexPage-CX2FppcJ.js +1 -0
  22. package/dist/public/assets/SettingsPage-BI2Olcvr.js +2 -0
  23. package/dist/public/assets/TerminalManagerPanel-B5MKGPy-.js +1 -0
  24. package/dist/public/assets/{TerminalPage-C4LNoPBp.js → TerminalPage-C2dTNGHK.js} +2 -2
  25. package/dist/public/assets/TerminalRuntimeFallbackModal-DAqOxFD8.js +1 -0
  26. package/dist/public/assets/{ToolFilesPage-47zbdgTW.js → ToolFilesPage-IsNwyE6T.js} +1 -1
  27. package/dist/public/assets/{ToolGitPage-Fuk_b_jg.js → ToolGitPage-BK1JBERN.js} +1 -1
  28. package/dist/public/assets/{ToolProcessesPage-sWSMWD-9.js → ToolProcessesPage-DwTYUQCK.js} +1 -1
  29. package/dist/public/assets/{ToolsHomePage-R1mZlbZi.js → ToolsHomePage-BLOy7lPg.js} +1 -1
  30. package/dist/public/assets/{WorkbenchLandingPage-CqmiFH2u.js → WorkbenchLandingPage-CqZKR6EA.js} +1 -1
  31. package/dist/public/assets/WorkbenchLayout-BksVkkFF.css +1 -0
  32. package/dist/public/assets/WorkbenchLayout-CJHQtwuL.js +1022 -0
  33. package/dist/public/assets/{WorkbenchModal-C7qoQElW.js → WorkbenchModal-BM-OeW-b.js} +1 -1
  34. package/dist/public/assets/WorkbenchShellRoute-2bKI6Q9k.js +1 -0
  35. package/dist/public/assets/WorkbenchShellRoute-BjuZD101.css +1 -0
  36. package/dist/public/assets/WorkspaceDebugDetailPage-BMsEN5iG.js +1 -0
  37. package/dist/public/assets/WorkspaceDetailPage-5H9Gosx2.js +1 -0
  38. package/dist/public/assets/WorkspaceHomePage-DQiXKgiP.js +1 -0
  39. package/dist/public/assets/{client-runtime-manager-wmCJZKYd.js → client-runtime-manager-CgPJq21V.js} +1 -1
  40. package/dist/public/assets/index-BARqMVSw.css +1 -0
  41. package/dist/public/assets/index-BUoNjVrY.js +50 -0
  42. package/dist/public/assets/{login-direct-candidate-resolver-BOAgTuUf.js → login-direct-candidate-resolver-CGaxAXV8.js} +1 -1
  43. package/dist/public/assets/{plugin-permission-copy-Cq99cnzV.js → plugin-permission-copy-BR9gWy8b.js} +1 -1
  44. package/dist/public/assets/{plugins-api-BQTV5DOp.js → plugins-api-CdCsrG2e.js} +1 -1
  45. package/dist/public/assets/{preferences-service-DJxbEEeg.js → preferences-service-lOhnlxzP.js} +1 -1
  46. package/dist/public/assets/{relay-entry-D-LfvdiX.js → relay-entry-CQpxTS8y.js} +1 -1
  47. package/dist/public/assets/{terminal-runtime-meta-BJmy8dyK.js → terminal-runtime-meta-oteTx66X.js} +1 -1
  48. package/dist/public/assets/useRegisteredDebugTemplates-Bu2ykZ6s.js +1 -0
  49. package/dist/public/assets/workbench-navigation-DlgXuFW2.js +1 -0
  50. package/dist/public/index.html +2 -2
  51. package/dist/server/config/env.d.ts +1 -0
  52. package/dist/server/config/env.js +3 -0
  53. package/dist/server/config/env.js.map +1 -1
  54. package/dist/server/middlewares/auth-guard.js +10 -5
  55. package/dist/server/middlewares/auth-guard.js.map +1 -1
  56. package/dist/server/modules/affairs-indexer/contracts/src/errors/app-error.d.ts +11 -0
  57. package/dist/server/modules/affairs-indexer/contracts/src/errors/app-error.js +22 -0
  58. package/dist/server/modules/affairs-indexer/contracts/src/errors/app-error.js.map +1 -0
  59. package/dist/server/modules/affairs-indexer/contracts/src/errors/error-codes.d.ts +23 -0
  60. package/dist/server/modules/affairs-indexer/contracts/src/errors/error-codes.js +23 -0
  61. package/dist/server/modules/affairs-indexer/contracts/src/errors/error-codes.js.map +1 -0
  62. package/dist/server/modules/affairs-indexer/contracts/src/index.d.ts +4 -0
  63. package/dist/server/modules/affairs-indexer/contracts/src/index.js +5 -0
  64. package/dist/server/modules/affairs-indexer/contracts/src/index.js.map +1 -0
  65. package/dist/server/modules/affairs-indexer/contracts/src/types/cli-command-context.d.ts +7 -0
  66. package/dist/server/modules/affairs-indexer/contracts/src/types/cli-command-context.js +2 -0
  67. package/dist/server/modules/affairs-indexer/contracts/src/types/cli-command-context.js.map +1 -0
  68. package/dist/server/modules/affairs-indexer/contracts/src/types/runtime-config.d.ts +16 -0
  69. package/dist/server/modules/affairs-indexer/contracts/src/types/runtime-config.js +2 -0
  70. package/dist/server/modules/affairs-indexer/contracts/src/types/runtime-config.js.map +1 -0
  71. package/dist/server/modules/affairs-indexer/core/src/config/load-runtime-config.d.ts +10 -0
  72. package/dist/server/modules/affairs-indexer/core/src/config/load-runtime-config.js +215 -0
  73. package/dist/server/modules/affairs-indexer/core/src/config/load-runtime-config.js.map +1 -0
  74. package/dist/server/modules/affairs-indexer/core/src/index.d.ts +31 -0
  75. package/dist/server/modules/affairs-indexer/core/src/index.js +32 -0
  76. package/dist/server/modules/affairs-indexer/core/src/index.js.map +1 -0
  77. package/dist/server/modules/affairs-indexer/core/src/logging/structured-logger.d.ts +20 -0
  78. package/dist/server/modules/affairs-indexer/core/src/logging/structured-logger.js +47 -0
  79. package/dist/server/modules/affairs-indexer/core/src/logging/structured-logger.js.map +1 -0
  80. package/dist/server/modules/affairs-indexer/core/src/parser/base-complex-parser-adapter.d.ts +17 -0
  81. package/dist/server/modules/affairs-indexer/core/src/parser/base-complex-parser-adapter.js +63 -0
  82. package/dist/server/modules/affairs-indexer/core/src/parser/base-complex-parser-adapter.js.map +1 -0
  83. package/dist/server/modules/affairs-indexer/core/src/parser/complex-document-skip-adapter.d.ts +12 -0
  84. package/dist/server/modules/affairs-indexer/core/src/parser/complex-document-skip-adapter.js +42 -0
  85. package/dist/server/modules/affairs-indexer/core/src/parser/complex-document-skip-adapter.js.map +1 -0
  86. package/dist/server/modules/affairs-indexer/core/src/parser/csv-parser-adapter.d.ts +7 -0
  87. package/dist/server/modules/affairs-indexer/core/src/parser/csv-parser-adapter.js +107 -0
  88. package/dist/server/modules/affairs-indexer/core/src/parser/csv-parser-adapter.js.map +1 -0
  89. package/dist/server/modules/affairs-indexer/core/src/parser/document-parser.d.ts +19 -0
  90. package/dist/server/modules/affairs-indexer/core/src/parser/document-parser.js +37 -0
  91. package/dist/server/modules/affairs-indexer/core/src/parser/document-parser.js.map +1 -0
  92. package/dist/server/modules/affairs-indexer/core/src/parser/docx-parser-adapter.d.ts +7 -0
  93. package/dist/server/modules/affairs-indexer/core/src/parser/docx-parser-adapter.js +123 -0
  94. package/dist/server/modules/affairs-indexer/core/src/parser/docx-parser-adapter.js.map +1 -0
  95. package/dist/server/modules/affairs-indexer/core/src/parser/openxml-utils.d.ts +8 -0
  96. package/dist/server/modules/affairs-indexer/core/src/parser/openxml-utils.js +111 -0
  97. package/dist/server/modules/affairs-indexer/core/src/parser/openxml-utils.js.map +1 -0
  98. package/dist/server/modules/affairs-indexer/core/src/parser/parser-adapter.d.ts +42 -0
  99. package/dist/server/modules/affairs-indexer/core/src/parser/parser-adapter.js +2 -0
  100. package/dist/server/modules/affairs-indexer/core/src/parser/parser-adapter.js.map +1 -0
  101. package/dist/server/modules/affairs-indexer/core/src/parser/parser-capability-registry.d.ts +18 -0
  102. package/dist/server/modules/affairs-indexer/core/src/parser/parser-capability-registry.js +91 -0
  103. package/dist/server/modules/affairs-indexer/core/src/parser/parser-capability-registry.js.map +1 -0
  104. package/dist/server/modules/affairs-indexer/core/src/parser/parser-router.d.ts +18 -0
  105. package/dist/server/modules/affairs-indexer/core/src/parser/parser-router.js +59 -0
  106. package/dist/server/modules/affairs-indexer/core/src/parser/parser-router.js.map +1 -0
  107. package/dist/server/modules/affairs-indexer/core/src/parser/parser-skip-repository.d.ts +48 -0
  108. package/dist/server/modules/affairs-indexer/core/src/parser/parser-skip-repository.js +193 -0
  109. package/dist/server/modules/affairs-indexer/core/src/parser/parser-skip-repository.js.map +1 -0
  110. package/dist/server/modules/affairs-indexer/core/src/parser/pdf-parser-adapter.d.ts +7 -0
  111. package/dist/server/modules/affairs-indexer/core/src/parser/pdf-parser-adapter.js +371 -0
  112. package/dist/server/modules/affairs-indexer/core/src/parser/pdf-parser-adapter.js.map +1 -0
  113. package/dist/server/modules/affairs-indexer/core/src/parser/plain-text-parser-adapter.d.ts +10 -0
  114. package/dist/server/modules/affairs-indexer/core/src/parser/plain-text-parser-adapter.js +55 -0
  115. package/dist/server/modules/affairs-indexer/core/src/parser/plain-text-parser-adapter.js.map +1 -0
  116. package/dist/server/modules/affairs-indexer/core/src/parser/plain-text-parser.d.ts +9 -0
  117. package/dist/server/modules/affairs-indexer/core/src/parser/plain-text-parser.js +2 -0
  118. package/dist/server/modules/affairs-indexer/core/src/parser/plain-text-parser.js.map +1 -0
  119. package/dist/server/modules/affairs-indexer/core/src/parser/pptx-parser-adapter.d.ts +7 -0
  120. package/dist/server/modules/affairs-indexer/core/src/parser/pptx-parser-adapter.js +130 -0
  121. package/dist/server/modules/affairs-indexer/core/src/parser/pptx-parser-adapter.js.map +1 -0
  122. package/dist/server/modules/affairs-indexer/core/src/parser/xlsx-parser-adapter.d.ts +7 -0
  123. package/dist/server/modules/affairs-indexer/core/src/parser/xlsx-parser-adapter.js +228 -0
  124. package/dist/server/modules/affairs-indexer/core/src/parser/xlsx-parser-adapter.js.map +1 -0
  125. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.d.ts +205 -0
  126. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.js +1471 -0
  127. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.js.map +1 -0
  128. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-write-repository.d.ts +161 -0
  129. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-write-repository.js +1350 -0
  130. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-write-repository.js.map +1 -0
  131. package/dist/server/modules/affairs-indexer/core/src/scanner/file-scanner.d.ts +32 -0
  132. package/dist/server/modules/affairs-indexer/core/src/scanner/file-scanner.js +208 -0
  133. package/dist/server/modules/affairs-indexer/core/src/scanner/file-scanner.js.map +1 -0
  134. package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.d.ts +30 -0
  135. package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.js +66 -0
  136. package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.js.map +1 -0
  137. package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.d.ts +33 -0
  138. package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.js +705 -0
  139. package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.js.map +1 -0
  140. package/dist/server/modules/affairs-indexer/core/src/services/indexer/allowed-extensions-diff-service.d.ts +80 -0
  141. package/dist/server/modules/affairs-indexer/core/src/services/indexer/allowed-extensions-diff-service.js +193 -0
  142. package/dist/server/modules/affairs-indexer/core/src/services/indexer/allowed-extensions-diff-service.js.map +1 -0
  143. package/dist/server/modules/affairs-indexer/core/src/services/indexer/text-indexer.d.ts +77 -0
  144. package/dist/server/modules/affairs-indexer/core/src/services/indexer/text-indexer.js +467 -0
  145. package/dist/server/modules/affairs-indexer/core/src/services/indexer/text-indexer.js.map +1 -0
  146. package/dist/server/modules/affairs-indexer/core/src/services/mcp/mcp-stdio-server.d.ts +17 -0
  147. package/dist/server/modules/affairs-indexer/core/src/services/mcp/mcp-stdio-server.js +264 -0
  148. package/dist/server/modules/affairs-indexer/core/src/services/mcp/mcp-stdio-server.js.map +1 -0
  149. package/dist/server/modules/affairs-indexer/core/src/services/search/offline-search-service.d.ts +11 -0
  150. package/dist/server/modules/affairs-indexer/core/src/services/search/offline-search-service.js +76 -0
  151. package/dist/server/modules/affairs-indexer/core/src/services/search/offline-search-service.js.map +1 -0
  152. package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.d.ts +26 -0
  153. package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.js +305 -0
  154. package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.js.map +1 -0
  155. package/dist/server/modules/affairs-indexer/core/src/services/tagging/tag-recompute-service.d.ts +53 -0
  156. package/dist/server/modules/affairs-indexer/core/src/services/tagging/tag-recompute-service.js +566 -0
  157. package/dist/server/modules/affairs-indexer/core/src/services/tagging/tag-recompute-service.js.map +1 -0
  158. package/dist/server/modules/affairs-indexer/core/src/services/watch/watch-service.d.ts +47 -0
  159. package/dist/server/modules/affairs-indexer/core/src/services/watch/watch-service.js +227 -0
  160. package/dist/server/modules/affairs-indexer/core/src/services/watch/watch-service.js.map +1 -0
  161. package/dist/server/modules/affairs-indexer/core/src/sqlite/catalog-schema.d.ts +5 -0
  162. package/dist/server/modules/affairs-indexer/core/src/sqlite/catalog-schema.js +245 -0
  163. package/dist/server/modules/affairs-indexer/core/src/sqlite/catalog-schema.js.map +1 -0
  164. package/dist/server/modules/affairs-indexer/core/src/sqlite/detect-catalog-schema.d.ts +14 -0
  165. package/dist/server/modules/affairs-indexer/core/src/sqlite/detect-catalog-schema.js +87 -0
  166. package/dist/server/modules/affairs-indexer/core/src/sqlite/detect-catalog-schema.js.map +1 -0
  167. package/dist/server/modules/affairs-indexer/core/src/sqlite/init-catalog.d.ts +13 -0
  168. package/dist/server/modules/affairs-indexer/core/src/sqlite/init-catalog.js +16 -0
  169. package/dist/server/modules/affairs-indexer/core/src/sqlite/init-catalog.js.map +1 -0
  170. package/dist/server/modules/affairs-indexer/core/src/sqlite/migration-runner.d.ts +22 -0
  171. package/dist/server/modules/affairs-indexer/core/src/sqlite/migration-runner.js +430 -0
  172. package/dist/server/modules/affairs-indexer/core/src/sqlite/migration-runner.js.map +1 -0
  173. package/dist/server/modules/affairs-indexer/core/src/sqlite/open-database.d.ts +26 -0
  174. package/dist/server/modules/affairs-indexer/core/src/sqlite/open-database.js +19 -0
  175. package/dist/server/modules/affairs-indexer/core/src/sqlite/open-database.js.map +1 -0
  176. package/dist/server/modules/affairs-indexer/core/src/tagging/simple-tag-inference.d.ts +21 -0
  177. package/dist/server/modules/affairs-indexer/core/src/tagging/simple-tag-inference.js +94 -0
  178. package/dist/server/modules/affairs-indexer/core/src/tagging/simple-tag-inference.js.map +1 -0
  179. package/dist/server/modules/affairs-indexer/core/src/utils/abort.d.ts +2 -0
  180. package/dist/server/modules/affairs-indexer/core/src/utils/abort.js +13 -0
  181. package/dist/server/modules/affairs-indexer/core/src/utils/abort.js.map +1 -0
  182. package/dist/server/modules/affairs-indexer/core/src/utils/file-streaming.d.ts +9 -0
  183. package/dist/server/modules/affairs-indexer/core/src/utils/file-streaming.js +64 -0
  184. package/dist/server/modules/affairs-indexer/core/src/utils/file-streaming.js.map +1 -0
  185. package/dist/server/modules/affairs-indexer/core/src/utils/root-command-lock.d.ts +10 -0
  186. package/dist/server/modules/affairs-indexer/core/src/utils/root-command-lock.js +230 -0
  187. package/dist/server/modules/affairs-indexer/core/src/utils/root-command-lock.js.map +1 -0
  188. package/dist/server/modules/affairs-indexer/core/src/utils/rss-log.d.ts +2 -0
  189. package/dist/server/modules/affairs-indexer/core/src/utils/rss-log.js +19 -0
  190. package/dist/server/modules/affairs-indexer/core/src/utils/rss-log.js.map +1 -0
  191. package/dist/server/modules/affairs-indexer/internal-command-runner.d.ts +31 -0
  192. package/dist/server/modules/affairs-indexer/internal-command-runner.js +643 -0
  193. package/dist/server/modules/affairs-indexer/internal-command-runner.js.map +1 -0
  194. package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +0 -49
  195. package/dist/server/modules/assistant-capability/assistant-capability-controller.js +10 -56
  196. package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
  197. package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +2 -46
  198. package/dist/server/modules/assistant-capability/assistant-capability-service.js +15 -158
  199. package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
  200. package/dist/server/modules/browser-runtime/opencli-bridge-browser-executor.d.ts +4 -2
  201. package/dist/server/modules/browser-runtime/opencli-bridge-browser-executor.js +62 -21
  202. package/dist/server/modules/browser-runtime/opencli-bridge-browser-executor.js.map +1 -1
  203. package/dist/server/modules/butler/butler-control-session-service.d.ts +3 -4
  204. package/dist/server/modules/butler/butler-control-session-service.js +39 -62
  205. package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
  206. package/dist/server/modules/butler/butler-controller.d.ts +11 -3
  207. package/dist/server/modules/butler/butler-controller.js +19 -4
  208. package/dist/server/modules/butler/butler-controller.js.map +1 -1
  209. package/dist/server/modules/butler/butler-follow-up-service.d.ts +3 -0
  210. package/dist/server/modules/butler/butler-follow-up-service.js +11 -1
  211. package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
  212. package/dist/server/modules/butler/butler-inbox-service.d.ts +3 -0
  213. package/dist/server/modules/butler/butler-inbox-service.js +14 -2
  214. package/dist/server/modules/butler/butler-inbox-service.js.map +1 -1
  215. package/dist/server/modules/butler/butler-profile-service.d.ts +1 -1
  216. package/dist/server/modules/butler/butler-profile-service.js +34 -63
  217. package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
  218. package/dist/server/modules/butler/butler-project-service.d.ts +1 -3
  219. package/dist/server/modules/butler/butler-project-service.js +1 -7
  220. package/dist/server/modules/butler/butler-project-service.js.map +1 -1
  221. package/dist/server/modules/butler/butler-session-service.d.ts +4 -0
  222. package/dist/server/modules/butler/butler-session-service.js +127 -0
  223. package/dist/server/modules/butler/butler-session-service.js.map +1 -1
  224. package/dist/server/modules/butler/butler-session-summary-service.js +0 -2
  225. package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
  226. package/dist/server/modules/butler/butler-workspace-context.d.ts +5 -1
  227. package/dist/server/modules/butler/butler-workspace-context.js +21 -12
  228. package/dist/server/modules/butler/butler-workspace-context.js.map +1 -1
  229. package/dist/server/modules/file/file-content-service.d.ts +11 -0
  230. package/dist/server/modules/file/file-content-service.js +55 -0
  231. package/dist/server/modules/file/file-content-service.js.map +1 -1
  232. package/dist/server/modules/file/file-controller.d.ts +36 -2
  233. package/dist/server/modules/file/file-controller.js +461 -19
  234. package/dist/server/modules/file/file-controller.js.map +1 -1
  235. package/dist/server/modules/file/file-preview-link-service.d.ts +1 -0
  236. package/dist/server/modules/file/file-preview-link-service.js +25 -0
  237. package/dist/server/modules/file/file-preview-link-service.js.map +1 -1
  238. package/dist/server/modules/file/file-preview-service.js +15 -4
  239. package/dist/server/modules/file/file-preview-service.js.map +1 -1
  240. package/dist/server/modules/file/file-preview-types.d.ts +9 -1
  241. package/dist/server/modules/file/file-preview-types.js +8 -1
  242. package/dist/server/modules/file/file-preview-types.js.map +1 -1
  243. package/dist/server/modules/file/file-search-service.js +200 -12
  244. package/dist/server/modules/file/file-search-service.js.map +1 -1
  245. package/dist/server/modules/file/recent-modified-file-service.d.ts +15 -0
  246. package/dist/server/modules/file/recent-modified-file-service.js +102 -0
  247. package/dist/server/modules/file/recent-modified-file-service.js.map +1 -0
  248. package/dist/server/modules/file/runtime/codingns-workspace-bridge.js +24 -5
  249. package/dist/server/modules/file/workspace-file-bridge-service.d.ts +20 -0
  250. package/dist/server/modules/file/workspace-file-bridge-service.js +22 -0
  251. package/dist/server/modules/file/workspace-file-bridge-service.js.map +1 -1
  252. package/dist/server/modules/file/workspace-file-bridge-watch-service.d.ts +9 -0
  253. package/dist/server/modules/file/workspace-file-bridge-watch-service.js +28 -0
  254. package/dist/server/modules/file/workspace-file-bridge-watch-service.js.map +1 -1
  255. package/dist/server/modules/file/workspace-index-apply-service.d.ts +25 -0
  256. package/dist/server/modules/file/workspace-index-apply-service.js +42 -0
  257. package/dist/server/modules/file/workspace-index-apply-service.js.map +1 -0
  258. package/dist/server/modules/office/office-controller.d.ts +15 -1
  259. package/dist/server/modules/office/office-controller.js +26 -1
  260. package/dist/server/modules/office/office-controller.js.map +1 -1
  261. package/dist/server/modules/office/onlyoffice-integration-service.d.ts +78 -0
  262. package/dist/server/modules/office/onlyoffice-integration-service.js +610 -0
  263. package/dist/server/modules/office/onlyoffice-integration-service.js.map +1 -0
  264. package/dist/server/modules/plugins/plugin-file-gateway-service.d.ts +12 -0
  265. package/dist/server/modules/plugins/plugin-file-gateway-service.js +13 -0
  266. package/dist/server/modules/plugins/plugin-file-gateway-service.js.map +1 -1
  267. package/dist/server/modules/preferences/profile-service.d.ts +1 -0
  268. package/dist/server/modules/preferences/profile-service.js +27 -3
  269. package/dist/server/modules/preferences/profile-service.js.map +1 -1
  270. package/dist/server/modules/sessions/codex-app-server-helper-process.js +0 -8
  271. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  272. package/dist/server/modules/sessions/session-controller.d.ts +1 -0
  273. package/dist/server/modules/sessions/session-controller.js +3 -0
  274. package/dist/server/modules/sessions/session-controller.js.map +1 -1
  275. package/dist/server/modules/sessions/session-history-service.d.ts +2 -0
  276. package/dist/server/modules/sessions/session-history-service.js +78 -3
  277. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  278. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +1 -0
  279. package/dist/server/modules/sessions/session-live-runtime-service.js +4 -0
  280. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  281. package/dist/server/modules/sessions/session-permission-request-service.js +0 -4
  282. package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
  283. package/dist/server/modules/sessions/workspace-session-instruction-watch-service.d.ts +23 -0
  284. package/dist/server/modules/sessions/workspace-session-instruction-watch-service.js +122 -0
  285. package/dist/server/modules/sessions/workspace-session-instruction-watch-service.js.map +1 -0
  286. package/dist/server/modules/sessions/workspace-session-runtime-context-service.d.ts +15 -0
  287. package/dist/server/modules/sessions/workspace-session-runtime-context-service.js +93 -10
  288. package/dist/server/modules/sessions/workspace-session-runtime-context-service.js.map +1 -1
  289. package/dist/server/modules/skills/builtin-skills/codingns-assistant/SKILL.md +6 -7
  290. package/dist/server/modules/skills/builtin-skills/codingns-assistant/references/cli-workflow.md +2 -3
  291. package/dist/server/modules/system/host-resource-controller.d.ts +7 -0
  292. package/dist/server/modules/system/host-resource-controller.js +12 -0
  293. package/dist/server/modules/system/host-resource-controller.js.map +1 -0
  294. package/dist/server/modules/system/host-resource-service.d.ts +54 -0
  295. package/dist/server/modules/system/host-resource-service.js +162 -0
  296. package/dist/server/modules/system/host-resource-service.js.map +1 -0
  297. package/dist/server/modules/tasks/observability-service.d.ts +12 -2
  298. package/dist/server/modules/tasks/observability-service.js +13 -1
  299. package/dist/server/modules/tasks/observability-service.js.map +1 -1
  300. package/dist/server/modules/tasks/task-helper-client.d.ts +36 -2
  301. package/dist/server/modules/tasks/task-helper-client.js +201 -19
  302. package/dist/server/modules/tasks/task-helper-client.js.map +1 -1
  303. package/dist/server/modules/tasks/task-helper-pool.d.ts +37 -0
  304. package/dist/server/modules/tasks/task-helper-pool.js +173 -0
  305. package/dist/server/modules/tasks/task-helper-pool.js.map +1 -0
  306. package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +27 -0
  307. package/dist/server/modules/tasks/task-helper-process-handlers.js +25 -1
  308. package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -1
  309. package/dist/server/modules/tasks/task-helper-process.js +75 -26
  310. package/dist/server/modules/tasks/task-helper-process.js.map +1 -1
  311. package/dist/server/modules/tasks/task-helper-scheduling.d.ts +11 -0
  312. package/dist/server/modules/tasks/task-helper-scheduling.js +43 -0
  313. package/dist/server/modules/tasks/task-helper-scheduling.js.map +1 -0
  314. package/dist/server/modules/tasks/task-lane-executors.js +19 -3
  315. package/dist/server/modules/tasks/task-lane-executors.js.map +1 -1
  316. package/dist/server/modules/tasks/task-manager.d.ts +1 -0
  317. package/dist/server/modules/tasks/task-manager.js +3 -0
  318. package/dist/server/modules/tasks/task-manager.js.map +1 -1
  319. package/dist/server/modules/tasks/task-registry.d.ts +1 -0
  320. package/dist/server/modules/tasks/task-registry.js +3 -0
  321. package/dist/server/modules/tasks/task-registry.js.map +1 -1
  322. package/dist/server/modules/tasks/task-scheduler.d.ts +6 -0
  323. package/dist/server/modules/tasks/task-scheduler.js +162 -7
  324. package/dist/server/modules/tasks/task-scheduler.js.map +1 -1
  325. package/dist/server/modules/tasks/task-types.d.ts +29 -3
  326. package/dist/server/modules/tasks/task-types.js +15 -2
  327. package/dist/server/modules/tasks/task-types.js.map +1 -1
  328. package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.d.ts +68 -0
  329. package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.js +303 -0
  330. package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.js.map +1 -0
  331. package/dist/server/modules/workbench/workbench-controller.d.ts +5 -0
  332. package/dist/server/modules/workbench/workbench-controller.js +31 -1
  333. package/dist/server/modules/workbench/workbench-controller.js.map +1 -1
  334. package/dist/server/modules/workbench/workbench-service.d.ts +9 -2
  335. package/dist/server/modules/workbench/workbench-service.js +55 -18
  336. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  337. package/dist/server/modules/workspace/affairs-library-controller.d.ts +125 -0
  338. package/dist/server/modules/workspace/affairs-library-controller.js +175 -0
  339. package/dist/server/modules/workspace/affairs-library-controller.js.map +1 -0
  340. package/dist/server/modules/workspace/affairs-library-debug-log.d.ts +23 -0
  341. package/dist/server/modules/workspace/affairs-library-debug-log.js +107 -0
  342. package/dist/server/modules/workspace/affairs-library-debug-log.js.map +1 -0
  343. package/dist/server/modules/workspace/affairs-library-dirty-watch-service.d.ts +52 -0
  344. package/dist/server/modules/workspace/affairs-library-dirty-watch-service.js +555 -0
  345. package/dist/server/modules/workspace/affairs-library-dirty-watch-service.js.map +1 -0
  346. package/dist/server/modules/workspace/affairs-library-preview-link-service.d.ts +30 -0
  347. package/dist/server/modules/workspace/affairs-library-preview-link-service.js +167 -0
  348. package/dist/server/modules/workspace/affairs-library-preview-link-service.js.map +1 -0
  349. package/dist/server/modules/workspace/affairs-library-refresh-contract.d.ts +56 -0
  350. package/dist/server/modules/workspace/affairs-library-refresh-contract.js +48 -0
  351. package/dist/server/modules/workspace/affairs-library-refresh-contract.js.map +1 -0
  352. package/dist/server/modules/workspace/affairs-library-service.d.ts +353 -0
  353. package/dist/server/modules/workspace/affairs-library-service.js +3895 -0
  354. package/dist/server/modules/workspace/affairs-library-service.js.map +1 -0
  355. package/dist/server/modules/workspace/affairs-lightweight-session-controller.d.ts +86 -0
  356. package/dist/server/modules/workspace/affairs-lightweight-session-controller.js +193 -0
  357. package/dist/server/modules/workspace/affairs-lightweight-session-controller.js.map +1 -0
  358. package/dist/server/modules/workspace/affairs-lightweight-session-service.d.ts +146 -0
  359. package/dist/server/modules/workspace/affairs-lightweight-session-service.js +1593 -0
  360. package/dist/server/modules/workspace/affairs-lightweight-session-service.js.map +1 -0
  361. package/dist/server/modules/workspace/affairs-tag-controller.d.ts +110 -0
  362. package/dist/server/modules/workspace/affairs-tag-controller.js +102 -0
  363. package/dist/server/modules/workspace/affairs-tag-controller.js.map +1 -0
  364. package/dist/server/modules/workspace/affairs-tag-service.d.ts +174 -0
  365. package/dist/server/modules/workspace/affairs-tag-service.js +719 -0
  366. package/dist/server/modules/workspace/affairs-tag-service.js.map +1 -0
  367. package/dist/server/modules/workspace/teable-api-client.d.ts +118 -0
  368. package/dist/server/modules/workspace/teable-api-client.js +142 -0
  369. package/dist/server/modules/workspace/teable-api-client.js.map +1 -0
  370. package/dist/server/modules/workspace/teable-catalog-controller.d.ts +18 -0
  371. package/dist/server/modules/workspace/teable-catalog-controller.js +17 -0
  372. package/dist/server/modules/workspace/teable-catalog-controller.js.map +1 -0
  373. package/dist/server/modules/workspace/teable-catalog-service.d.ts +36 -0
  374. package/dist/server/modules/workspace/teable-catalog-service.js +124 -0
  375. package/dist/server/modules/workspace/teable-catalog-service.js.map +1 -0
  376. package/dist/server/modules/workspace/teable-credential-service.d.ts +8 -0
  377. package/dist/server/modules/workspace/teable-credential-service.js +37 -0
  378. package/dist/server/modules/workspace/teable-credential-service.js.map +1 -0
  379. package/dist/server/modules/workspace/teable-field-mapping-controller.d.ts +25 -0
  380. package/dist/server/modules/workspace/teable-field-mapping-controller.js +31 -0
  381. package/dist/server/modules/workspace/teable-field-mapping-controller.js.map +1 -0
  382. package/dist/server/modules/workspace/teable-field-mapping-service.d.ts +38 -0
  383. package/dist/server/modules/workspace/teable-field-mapping-service.js +215 -0
  384. package/dist/server/modules/workspace/teable-field-mapping-service.js.map +1 -0
  385. package/dist/server/modules/workspace/teable-global-binding-controller.d.ts +22 -0
  386. package/dist/server/modules/workspace/teable-global-binding-controller.js +25 -0
  387. package/dist/server/modules/workspace/teable-global-binding-controller.js.map +1 -0
  388. package/dist/server/modules/workspace/teable-global-binding-service.d.ts +35 -0
  389. package/dist/server/modules/workspace/teable-global-binding-service.js +151 -0
  390. package/dist/server/modules/workspace/teable-global-binding-service.js.map +1 -0
  391. package/dist/server/modules/workspace/teable-mirror-sync-controller.d.ts +29 -0
  392. package/dist/server/modules/workspace/teable-mirror-sync-controller.js +50 -0
  393. package/dist/server/modules/workspace/teable-mirror-sync-controller.js.map +1 -0
  394. package/dist/server/modules/workspace/teable-mirror-sync-service.d.ts +157 -0
  395. package/dist/server/modules/workspace/teable-mirror-sync-service.js +917 -0
  396. package/dist/server/modules/workspace/teable-mirror-sync-service.js.map +1 -0
  397. package/dist/server/modules/workspace/teable-runtime-controller.d.ts +58 -0
  398. package/dist/server/modules/workspace/teable-runtime-controller.js +60 -0
  399. package/dist/server/modules/workspace/teable-runtime-controller.js.map +1 -0
  400. package/dist/server/modules/workspace/teable-runtime-service.d.ts +96 -0
  401. package/dist/server/modules/workspace/teable-runtime-service.js +362 -0
  402. package/dist/server/modules/workspace/teable-runtime-service.js.map +1 -0
  403. package/dist/server/modules/workspace/teable-workbench-sync-config-controller.d.ts +22 -0
  404. package/dist/server/modules/workspace/teable-workbench-sync-config-controller.js +20 -0
  405. package/dist/server/modules/workspace/teable-workbench-sync-config-controller.js.map +1 -0
  406. package/dist/server/modules/workspace/teable-workbench-sync-config-service.d.ts +22 -0
  407. package/dist/server/modules/workspace/teable-workbench-sync-config-service.js +159 -0
  408. package/dist/server/modules/workspace/teable-workbench-sync-config-service.js.map +1 -0
  409. package/dist/server/modules/workspace/workspace-controller.d.ts +2 -1
  410. package/dist/server/modules/workspace/workspace-controller.js +8 -2
  411. package/dist/server/modules/workspace/workspace-controller.js.map +1 -1
  412. package/dist/server/modules/workspace/workspace-service.js +60 -9
  413. package/dist/server/modules/workspace/workspace-service.js.map +1 -1
  414. package/dist/server/routes/affairs.d.ts +11 -0
  415. package/dist/server/routes/affairs.js +126 -0
  416. package/dist/server/routes/affairs.js.map +1 -0
  417. package/dist/server/routes/assistant.js +0 -5
  418. package/dist/server/routes/assistant.js.map +1 -1
  419. package/dist/server/routes/files.js +5 -0
  420. package/dist/server/routes/files.js.map +1 -1
  421. package/dist/server/routes/office.js +4 -0
  422. package/dist/server/routes/office.js.map +1 -1
  423. package/dist/server/routes/system.d.ts +2 -1
  424. package/dist/server/routes/system.js +2 -1
  425. package/dist/server/routes/system.js.map +1 -1
  426. package/dist/server/routes/workbench.js +15 -0
  427. package/dist/server/routes/workbench.js.map +1 -1
  428. package/dist/server/routes/workspaces.d.ts +4 -1
  429. package/dist/server/routes/workspaces.js +56 -1
  430. package/dist/server/routes/workspaces.js.map +1 -1
  431. package/dist/server/server/create-server.d.ts +20 -2
  432. package/dist/server/server/create-server.js +180 -33
  433. package/dist/server/server/create-server.js.map +1 -1
  434. package/dist/server/shared/http/error-handler.js +10 -0
  435. package/dist/server/shared/http/error-handler.js.map +1 -1
  436. package/dist/server/storage/repositories/affairs-assistant-session-snapshot-repository.d.ts +10 -0
  437. package/dist/server/storage/repositories/affairs-assistant-session-snapshot-repository.js +47 -0
  438. package/dist/server/storage/repositories/affairs-assistant-session-snapshot-repository.js.map +1 -0
  439. package/dist/server/storage/repositories/butler-profile-repository.js +7 -3
  440. package/dist/server/storage/repositories/butler-profile-repository.js.map +1 -1
  441. package/dist/server/storage/repositories/office-onlyoffice-setting-repository.d.ts +19 -0
  442. package/dist/server/storage/repositories/office-onlyoffice-setting-repository.js +55 -0
  443. package/dist/server/storage/repositories/office-onlyoffice-setting-repository.js.map +1 -0
  444. package/dist/server/storage/repositories/session-index-repository.js +9 -2
  445. package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
  446. package/dist/server/storage/repositories/user-affairs-library-setting-repository.d.ts +10 -0
  447. package/dist/server/storage/repositories/user-affairs-library-setting-repository.js +72 -0
  448. package/dist/server/storage/repositories/user-affairs-library-setting-repository.js.map +1 -0
  449. package/dist/server/storage/repositories/user-preference-profile-repository.js +6 -3
  450. package/dist/server/storage/repositories/user-preference-profile-repository.js.map +1 -1
  451. package/dist/server/storage/repositories/user-teable-credential-repository.d.ts +9 -0
  452. package/dist/server/storage/repositories/user-teable-credential-repository.js +45 -0
  453. package/dist/server/storage/repositories/user-teable-credential-repository.js.map +1 -0
  454. package/dist/server/storage/repositories/user-teable-field-mapping-repository.d.ts +10 -0
  455. package/dist/server/storage/repositories/user-teable-field-mapping-repository.js +69 -0
  456. package/dist/server/storage/repositories/user-teable-field-mapping-repository.js.map +1 -0
  457. package/dist/server/storage/repositories/user-teable-global-setting-repository.d.ts +8 -0
  458. package/dist/server/storage/repositories/user-teable-global-setting-repository.js +52 -0
  459. package/dist/server/storage/repositories/user-teable-global-setting-repository.js.map +1 -0
  460. package/dist/server/storage/repositories/user-teable-mirror-record-mapping-repository.d.ts +9 -0
  461. package/dist/server/storage/repositories/user-teable-mirror-record-mapping-repository.js +66 -0
  462. package/dist/server/storage/repositories/user-teable-mirror-record-mapping-repository.js.map +1 -0
  463. package/dist/server/storage/repositories/user-teable-mirror-table-binding-repository.d.ts +9 -0
  464. package/dist/server/storage/repositories/user-teable-mirror-table-binding-repository.js +67 -0
  465. package/dist/server/storage/repositories/user-teable-mirror-table-binding-repository.js.map +1 -0
  466. package/dist/server/storage/repositories/user-teable-sync-log-repository.d.ts +14 -0
  467. package/dist/server/storage/repositories/user-teable-sync-log-repository.js +97 -0
  468. package/dist/server/storage/repositories/user-teable-sync-log-repository.js.map +1 -0
  469. package/dist/server/storage/repositories/user-teable-workbench-sync-config-repository.d.ts +8 -0
  470. package/dist/server/storage/repositories/user-teable-workbench-sync-config-repository.js +55 -0
  471. package/dist/server/storage/repositories/user-teable-workbench-sync-config-repository.js.map +1 -0
  472. package/dist/server/storage/repositories/workspace-navigation-state-repository.d.ts +3 -0
  473. package/dist/server/storage/repositories/workspace-navigation-state-repository.js +47 -4
  474. package/dist/server/storage/repositories/workspace-navigation-state-repository.js.map +1 -1
  475. package/dist/server/storage/sqlite/client.js +633 -123
  476. package/dist/server/storage/sqlite/client.js.map +1 -1
  477. package/dist/server/storage/sqlite/schema.sql +214 -25
  478. package/dist/server/types/domain.d.ts +133 -20
  479. package/dist/server/ws/workbench-ws-hub.js +2 -2
  480. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  481. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-permissions.js +0 -2
  482. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-permissions.js.map +1 -1
  483. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +0 -6
  484. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  485. package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.d.ts +22 -3
  486. package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js +29 -2
  487. package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js.map +1 -1
  488. package/node_modules/@codingns/session-sync-core/package.json +3 -1
  489. package/package.json +1 -1
  490. package/dist/public/assets/AdaptiveButlerPage-B153lk5H.css +0 -1
  491. package/dist/public/assets/AdaptiveButlerPage-CJw8Ae62.js +0 -3
  492. package/dist/public/assets/DesktopModal-D_A8sgQU.js +0 -1
  493. package/dist/public/assets/DesktopWindowPage-DK7L7osV.js +0 -2
  494. package/dist/public/assets/FileContextPanel-BdCoubcJ.js +0 -1
  495. package/dist/public/assets/GitSidebar-BeZ0hj7A.js +0 -6
  496. package/dist/public/assets/MobileCreateSessionSheet-DfLMVu8q.js +0 -1
  497. package/dist/public/assets/MobileSheet-5kZ-w-gU.js +0 -1
  498. package/dist/public/assets/MobileWorkspaceSwitcherHeader-C6JMiOq_.js +0 -1
  499. package/dist/public/assets/PluginContainerPage-BlY-xJDh.js +0 -1
  500. package/dist/public/assets/SessionIndexPage-DkBp9Mqz.js +0 -1
  501. package/dist/public/assets/SettingsPage-C-ASmJAG.js +0 -2
  502. package/dist/public/assets/TerminalManagerPanel-NVZRxxmH.js +0 -1
  503. package/dist/public/assets/TerminalRuntimeFallbackModal-Bzum5nZ0.js +0 -1
  504. package/dist/public/assets/WorkbenchLayout-OFi6CWgH.js +0 -244
  505. package/dist/public/assets/WorkbenchShellRoute-B4XB8SwG.css +0 -1
  506. package/dist/public/assets/WorkbenchShellRoute-BAQe_E0O.js +0 -1
  507. package/dist/public/assets/WorkspaceDebugDetailPage-DhKa6e9y.js +0 -1
  508. package/dist/public/assets/WorkspaceDetailPage-BPsrFffw.js +0 -1
  509. package/dist/public/assets/WorkspaceHomePage-KAtqZOAb.js +0 -1
  510. package/dist/public/assets/file-tree-icon-Mg1DiBRX.js +0 -590
  511. package/dist/public/assets/index-C4t-vvqk.css +0 -1
  512. package/dist/public/assets/index-CL97fwWB.js +0 -42
  513. package/dist/public/assets/realtime-client-CLafKzzJ.js +0 -1
  514. package/dist/public/assets/useRegisteredDebugTemplates-DQAWVdCo.js +0 -1
  515. package/dist/public/assets/workbench-navigation-MEzCSmsK.js +0 -1
@@ -0,0 +1,1593 @@
1
+ import { promises as fs } from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { AppError } from "../../shared/errors/app-error.js";
5
+ import { createId } from "../../shared/utils/id.js";
6
+ const LIGHTWEIGHT_PROVIDER_IDS = new Set(["codex", "claude-code"]);
7
+ const LIGHTWEIGHT_STORAGE_VERSION = 1;
8
+ const DEFAULT_CLAUDE_MODEL = "claude-sonnet-4-20250514";
9
+ const DEFAULT_OPENAI_MODEL = "gpt-5.4";
10
+ const ANTHROPIC_API_VERSION = "2023-06-01";
11
+ const LIGHTWEIGHT_SESSION_TMP_FILE_SUFFIX = ".tmp";
12
+ const LIGHTWEIGHT_SESSION_READ_RETRY_DELAYS_MS = [12, 40];
13
+ const LIGHTWEIGHT_SYSTEM_PROMPT = [
14
+ "你是 CodingNS 的事务轻量会话。",
15
+ "你的职责是快速问答、联网搜索、轻量分析。",
16
+ "你没有本地文件、终端、浏览器自动化、工作区读写、MCP、本地工具权限。",
17
+ "如果用户要求你读取本地目录、执行命令、修改文件、调用本地工具,必须明确说当前轻量模式做不到,并建议切到 Agent 会话。",
18
+ "需要最新信息时,优先使用联网搜索,再给结论。",
19
+ "回答直接、清楚、少废话。"
20
+ ].join("\n");
21
+ export class AffairsLightweightSessionService {
22
+ hostDataRootDir;
23
+ sessionLocks = new Map();
24
+ sessionDocumentCache = new Map();
25
+ teableMirrorSyncNotifier = null;
26
+ constructor(hostDataRootDir) {
27
+ this.hostDataRootDir = hostDataRootDir;
28
+ }
29
+ configureTeableMirrorSyncNotifier(notifier) {
30
+ this.teableMirrorSyncNotifier = notifier;
31
+ }
32
+ async listSessions(workspaceId, userId) {
33
+ const workspaceDir = this.resolveWorkspaceDir(workspaceId);
34
+ const entries = await safeReadDir(workspaceDir);
35
+ const sessions = await Promise.all(entries
36
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
37
+ .map(async (entry) => {
38
+ const document = await this.readSessionDocumentByPath(path.join(workspaceDir, entry.name));
39
+ return document?.userId === userId ? document.session : null;
40
+ }));
41
+ return sessions
42
+ .filter((item) => Boolean(item))
43
+ .sort((left, right) => {
44
+ const leftValue = left.lastMessageAt ?? left.updatedAt;
45
+ const rightValue = right.lastMessageAt ?? right.updatedAt;
46
+ return rightValue.localeCompare(leftValue);
47
+ });
48
+ }
49
+ async getSession(workspaceId, sessionId, userId) {
50
+ const document = await this.requireSessionDocument(workspaceId, sessionId, userId);
51
+ return document.session;
52
+ }
53
+ async readMessages(workspaceId, sessionId, userId) {
54
+ const document = await this.requireSessionDocument(workspaceId, sessionId, userId);
55
+ return {
56
+ messages: document.messages,
57
+ cursor: null,
58
+ nextCursor: null,
59
+ total: document.messages.length
60
+ };
61
+ }
62
+ async markSessionSeen(workspaceId, sessionId, userId, seenAt) {
63
+ await this.waitForSessionIdle(sessionId);
64
+ const document = await this.requireSessionDocument(workspaceId, sessionId, userId);
65
+ const normalizedSeenAt = normalizeOptionalTimestamp(seenAt) ?? new Date().toISOString();
66
+ const nextActivityState = document.session.activityState === "completed_unread"
67
+ ? "idle"
68
+ : document.session.activityState;
69
+ await this.writeSessionDocument({
70
+ ...document,
71
+ session: {
72
+ ...document.session,
73
+ lastSeenAt: normalizedSeenAt,
74
+ activityState: nextActivityState
75
+ }
76
+ });
77
+ }
78
+ async renameSessionTitle(workspaceId, sessionId, userId, title) {
79
+ await this.waitForSessionIdle(sessionId);
80
+ const normalizedTitle = title.trim();
81
+ if (!normalizedTitle) {
82
+ throw new AppError({
83
+ statusCode: 400,
84
+ errorCode: "INVALID_INPUT",
85
+ detail: "事务轻量会话标题不能为空",
86
+ field: "title"
87
+ });
88
+ }
89
+ return this.updateSessionSummary(workspaceId, sessionId, userId, (session) => ({
90
+ ...session,
91
+ title: normalizedTitle
92
+ }), "session_title_renamed");
93
+ }
94
+ async updateSessionArchiveState(workspaceId, sessionId, userId, archived) {
95
+ await this.waitForSessionIdle(sessionId);
96
+ return this.updateSessionSummary(workspaceId, sessionId, userId, (session) => ({
97
+ ...session,
98
+ isArchived: archived
99
+ }), "session_archive_changed");
100
+ }
101
+ async updateSessionFavoriteState(workspaceId, sessionId, userId, favorite) {
102
+ await this.waitForSessionIdle(sessionId);
103
+ return this.updateSessionSummary(workspaceId, sessionId, userId, (session) => ({
104
+ ...session,
105
+ isFavorite: favorite
106
+ }), "session_favorite_changed");
107
+ }
108
+ async deleteSession(workspaceId, sessionId, userId) {
109
+ await this.waitForSessionIdle(sessionId);
110
+ await this.requireSessionDocument(workspaceId, sessionId, userId);
111
+ await fs.unlink(this.resolveSessionFilePath(workspaceId, sessionId));
112
+ this.sessionDocumentCache.delete(sessionId);
113
+ this.notifyTeableSessionChanged(userId, `session_deleted:${workspaceId}:${sessionId}`);
114
+ }
115
+ async startSession(input) {
116
+ const sessionId = createId();
117
+ const clientRequestId = normalizeClientRequestId(input.clientRequestId);
118
+ const acceptedAt = new Date().toISOString();
119
+ const sessionFilePath = this.resolveSessionFilePath(input.workspaceId, sessionId);
120
+ const providerSessionId = `affairs-lightweight:${input.provider}:${sessionId}`;
121
+ const session = {
122
+ sessionId,
123
+ workspaceId: input.workspaceId,
124
+ provider: input.provider,
125
+ providerSessionId,
126
+ rawStoreRef: sessionFilePath,
127
+ providerConfigMode: "global-default",
128
+ providerPresetId: null,
129
+ parentSessionId: null,
130
+ isSubagent: false,
131
+ subagentLabel: null,
132
+ isArchived: false,
133
+ isFavorite: false,
134
+ title: buildDraftTitle(input.content),
135
+ messageCount: 0,
136
+ lastMessageAt: null,
137
+ createdAt: acceptedAt,
138
+ updatedAt: acceptedAt,
139
+ syncStatus: "idle",
140
+ syncCursor: null,
141
+ lastSyncAt: null,
142
+ lastErrorCode: null,
143
+ lastErrorDetail: null,
144
+ resumedAt: null,
145
+ runningState: "starting",
146
+ activitySource: "runtime",
147
+ lastEventAt: acceptedAt,
148
+ completedAt: null,
149
+ lastSeenAt: null,
150
+ activityState: "running"
151
+ };
152
+ const document = {
153
+ version: LIGHTWEIGHT_STORAGE_VERSION,
154
+ userId: input.userId,
155
+ session,
156
+ messages: []
157
+ };
158
+ await this.writeSessionDocument(document);
159
+ this.notifyTeableSessionChanged(input.userId, `session_started:${input.workspaceId}:${sessionId}`);
160
+ return this.runTurn(document, {
161
+ workspaceId: input.workspaceId,
162
+ userId: input.userId,
163
+ sessionId,
164
+ content: input.content,
165
+ clientRequestId,
166
+ model: input.model ?? null,
167
+ reasoningLevel: input.reasoningLevel ?? null,
168
+ attachments: input.attachments ?? []
169
+ });
170
+ }
171
+ async sendMessage(input) {
172
+ const document = await this.requireSessionDocument(input.workspaceId, input.sessionId, input.userId);
173
+ return this.runTurn(document, {
174
+ ...input,
175
+ clientRequestId: normalizeClientRequestId(input.clientRequestId)
176
+ });
177
+ }
178
+ async startSessionStream(input, onEvent) {
179
+ const sessionId = createId();
180
+ const clientRequestId = normalizeClientRequestId(input.clientRequestId);
181
+ const acceptedAt = new Date().toISOString();
182
+ const sessionFilePath = this.resolveSessionFilePath(input.workspaceId, sessionId);
183
+ const providerSessionId = `affairs-lightweight:${input.provider}:${sessionId}`;
184
+ const session = {
185
+ sessionId,
186
+ workspaceId: input.workspaceId,
187
+ provider: input.provider,
188
+ providerSessionId,
189
+ rawStoreRef: sessionFilePath,
190
+ providerConfigMode: "global-default",
191
+ providerPresetId: null,
192
+ parentSessionId: null,
193
+ isSubagent: false,
194
+ subagentLabel: null,
195
+ isArchived: false,
196
+ isFavorite: false,
197
+ title: buildDraftTitle(input.content),
198
+ messageCount: 0,
199
+ lastMessageAt: null,
200
+ createdAt: acceptedAt,
201
+ updatedAt: acceptedAt,
202
+ syncStatus: "idle",
203
+ syncCursor: null,
204
+ lastSyncAt: null,
205
+ lastErrorCode: null,
206
+ lastErrorDetail: null,
207
+ resumedAt: null,
208
+ runningState: "starting",
209
+ activitySource: "runtime",
210
+ lastEventAt: acceptedAt,
211
+ completedAt: null,
212
+ lastSeenAt: null,
213
+ activityState: "running"
214
+ };
215
+ const document = {
216
+ version: LIGHTWEIGHT_STORAGE_VERSION,
217
+ userId: input.userId,
218
+ session,
219
+ messages: []
220
+ };
221
+ await this.writeSessionDocument(document);
222
+ await this.runTurn(document, {
223
+ workspaceId: input.workspaceId,
224
+ userId: input.userId,
225
+ sessionId,
226
+ content: input.content,
227
+ clientRequestId,
228
+ model: input.model ?? null,
229
+ reasoningLevel: input.reasoningLevel ?? null,
230
+ attachments: input.attachments ?? []
231
+ }, onEvent);
232
+ }
233
+ async sendMessageStream(input, onEvent) {
234
+ const document = await this.requireSessionDocument(input.workspaceId, input.sessionId, input.userId);
235
+ await this.runTurn(document, {
236
+ ...input,
237
+ clientRequestId: normalizeClientRequestId(input.clientRequestId)
238
+ }, onEvent);
239
+ }
240
+ async runTurn(baseDocument, input, onEvent) {
241
+ const existingLock = this.sessionLocks.get(baseDocument.session.sessionId);
242
+ if (existingLock) {
243
+ throw new AppError({
244
+ statusCode: 409,
245
+ errorCode: "SESSION_BUSY",
246
+ detail: "当前轻量会话还在回复上一条消息"
247
+ });
248
+ }
249
+ const job = this.runTurnInternal(baseDocument, input, onEvent)
250
+ .finally(() => {
251
+ this.sessionLocks.delete(baseDocument.session.sessionId);
252
+ });
253
+ this.sessionLocks.set(baseDocument.session.sessionId, job);
254
+ return job;
255
+ }
256
+ async runTurnInternal(baseDocument, input, onEvent) {
257
+ validateLightweightProvider(baseDocument.session.provider);
258
+ const now = new Date().toISOString();
259
+ const document = await this.requireSessionDocument(input.workspaceId, input.sessionId, input.userId);
260
+ const provider = document.session.provider;
261
+ const userMessage = createUserMessage({
262
+ provider,
263
+ providerSessionId: document.session.providerSessionId,
264
+ sessionId: document.session.sessionId,
265
+ content: input.content,
266
+ clientRequestId: input.clientRequestId,
267
+ sequence: document.messages.length + 1,
268
+ timestamp: now,
269
+ rawStoreRef: document.session.rawStoreRef,
270
+ attachments: normalizeLightweightMessageAttachments(input.attachments ?? [], input.clientRequestId)
271
+ });
272
+ const runningDocument = {
273
+ ...document,
274
+ session: {
275
+ ...document.session,
276
+ updatedAt: now,
277
+ lastMessageAt: now,
278
+ lastEventAt: now,
279
+ runningState: "running",
280
+ activityState: "running",
281
+ completedAt: null,
282
+ syncStatus: "syncing",
283
+ lastSyncAt: now,
284
+ lastErrorCode: null,
285
+ lastErrorDetail: null,
286
+ messageCount: document.messages.length + 1,
287
+ title: document.session.messageCount === 0 ? buildDraftTitle(input.content) : document.session.title
288
+ },
289
+ messages: [...document.messages, userMessage]
290
+ };
291
+ await this.writeSessionDocument(runningDocument);
292
+ await onEvent?.({
293
+ type: "started",
294
+ session: runningDocument.session,
295
+ acceptedAt: now,
296
+ clientRequestId: input.clientRequestId,
297
+ userMessage
298
+ });
299
+ let workingDocument = runningDocument;
300
+ try {
301
+ const handleToolEvent = async (event) => {
302
+ workingDocument = upsertToolLifecycleMessage({
303
+ document: workingDocument,
304
+ event,
305
+ observedAt: new Date().toISOString()
306
+ });
307
+ await this.writeSessionDocument(workingDocument);
308
+ await onEvent?.({ type: "tool", ...event });
309
+ };
310
+ const assistantContent = provider === "codex"
311
+ ? await this.generateOpenAiResponse(runningDocument, input, onEvent
312
+ ? async (delta) => {
313
+ await onEvent({ type: "delta", delta });
314
+ }
315
+ : undefined, handleToolEvent)
316
+ : await this.generateAnthropicResponse(runningDocument, input, onEvent
317
+ ? async (delta) => {
318
+ await onEvent({ type: "delta", delta });
319
+ }
320
+ : undefined, handleToolEvent);
321
+ const completedAt = new Date().toISOString();
322
+ const assistantMessage = createAssistantMessage({
323
+ provider,
324
+ providerSessionId: workingDocument.session.providerSessionId,
325
+ sessionId: workingDocument.session.sessionId,
326
+ content: assistantContent,
327
+ sequence: workingDocument.messages.length + 1,
328
+ timestamp: completedAt,
329
+ rawStoreRef: workingDocument.session.rawStoreRef
330
+ });
331
+ const completedDocument = {
332
+ ...workingDocument,
333
+ session: {
334
+ ...workingDocument.session,
335
+ updatedAt: completedAt,
336
+ lastMessageAt: completedAt,
337
+ lastEventAt: completedAt,
338
+ completedAt,
339
+ runningState: "completed",
340
+ activityState: "completed_unread",
341
+ syncStatus: "idle",
342
+ lastSyncAt: completedAt,
343
+ messageCount: workingDocument.messages.length + 1
344
+ },
345
+ messages: [...workingDocument.messages, assistantMessage]
346
+ };
347
+ await this.writeSessionDocument(completedDocument);
348
+ this.notifyTeableSessionChanged(input.userId, `session_completed:${input.workspaceId}:${baseDocument.session.sessionId}`);
349
+ const result = {
350
+ session: completedDocument.session,
351
+ acceptedAt: now,
352
+ clientRequestId: input.clientRequestId,
353
+ userMessage,
354
+ assistantMessage,
355
+ messages: completedDocument.messages
356
+ };
357
+ await onEvent?.({
358
+ type: "completed",
359
+ result
360
+ });
361
+ return result;
362
+ }
363
+ catch (error) {
364
+ const failedAt = new Date().toISOString();
365
+ const failureMessage = getErrorMessage(error);
366
+ const failedDocument = {
367
+ ...workingDocument,
368
+ session: {
369
+ ...workingDocument.session,
370
+ updatedAt: failedAt,
371
+ lastEventAt: failedAt,
372
+ completedAt: failedAt,
373
+ runningState: "failed",
374
+ activityState: "completed_unread",
375
+ syncStatus: "error",
376
+ lastSyncAt: failedAt,
377
+ lastErrorCode: error instanceof AppError ? error.errorCode : "LIGHTWEIGHT_RUNTIME_FAILED",
378
+ lastErrorDetail: failureMessage,
379
+ messageCount: workingDocument.messages.length
380
+ }
381
+ };
382
+ await this.writeSessionDocument(failedDocument);
383
+ this.notifyTeableSessionChanged(input.userId, `session_failed:${input.workspaceId}:${baseDocument.session.sessionId}`);
384
+ await onEvent?.({
385
+ type: "error",
386
+ errorCode: error instanceof AppError ? error.errorCode : "LIGHTWEIGHT_RUNTIME_FAILED",
387
+ detail: failureMessage
388
+ });
389
+ throw error;
390
+ }
391
+ }
392
+ async generateOpenAiResponse(document, input, onDelta, onTool) {
393
+ if (onDelta) {
394
+ const streamed = await this.generateOpenAiResponseStream(document, input, onDelta, onTool);
395
+ if (streamed) {
396
+ return streamed;
397
+ }
398
+ }
399
+ return this.generateOpenAiResponseSync(document, input);
400
+ }
401
+ async generateAnthropicResponse(document, input, onDelta, onTool) {
402
+ if (onDelta) {
403
+ const streamed = await this.generateAnthropicResponseStream(document, input, onDelta, onTool);
404
+ if (streamed) {
405
+ return streamed;
406
+ }
407
+ }
408
+ return this.generateAnthropicResponseSync(document, input);
409
+ }
410
+ async generateOpenAiResponseSync(document, input) {
411
+ const runtime = await this.readOpenAiRuntimeConfig(input.model?.trim() || null);
412
+ const responsePayload = createOpenAiResponsesPayload({
413
+ model: runtime.model,
414
+ messages: document.messages,
415
+ reasoningLevel: input.reasoningLevel ?? null,
416
+ activeClientRequestId: input.clientRequestId,
417
+ attachments: normalizeLightweightRuntimeAttachments(input.attachments ?? [], input.clientRequestId)
418
+ });
419
+ const headers = {
420
+ "content-type": "application/json",
421
+ authorization: `Bearer ${runtime.apiKey}`
422
+ };
423
+ const response = await postJsonWithFallbacks({
424
+ baseUrl: runtime.baseUrl,
425
+ pathCandidates: ["responses", "v1/responses"],
426
+ init: {
427
+ method: "POST",
428
+ headers,
429
+ body: JSON.stringify(responsePayload)
430
+ }
431
+ });
432
+ const body = await parseJsonResponse(response);
433
+ if (!response.ok) {
434
+ throw createUpstreamError("OPENAI_LIGHTWEIGHT_FAILED", body, response.status);
435
+ }
436
+ const outputText = extractOpenAiResponseText(body);
437
+ if (outputText) {
438
+ return outputText;
439
+ }
440
+ const fallbackResponse = await postJsonWithFallbacks({
441
+ baseUrl: runtime.baseUrl,
442
+ pathCandidates: ["v1/chat/completions", "chat/completions"],
443
+ init: {
444
+ method: "POST",
445
+ headers,
446
+ body: JSON.stringify(createOpenAiChatPayload({
447
+ model: runtime.model,
448
+ messages: document.messages,
449
+ activeClientRequestId: input.clientRequestId,
450
+ attachments: normalizeLightweightRuntimeAttachments(input.attachments ?? [], input.clientRequestId)
451
+ }))
452
+ }
453
+ });
454
+ const fallbackBody = await parseJsonResponse(fallbackResponse);
455
+ if (!fallbackResponse.ok) {
456
+ throw createUpstreamError("OPENAI_LIGHTWEIGHT_FAILED", fallbackBody, fallbackResponse.status);
457
+ }
458
+ const fallbackText = extractOpenAiResponseText(fallbackBody);
459
+ if (!fallbackText) {
460
+ throw new AppError({
461
+ statusCode: 502,
462
+ errorCode: "OPENAI_LIGHTWEIGHT_EMPTY",
463
+ detail: "轻量 Codex 没有返回正文"
464
+ });
465
+ }
466
+ return fallbackText;
467
+ }
468
+ async generateAnthropicResponseSync(document, input) {
469
+ const runtime = await this.readAnthropicRuntimeConfig(input.model?.trim() || null);
470
+ let messages = document.messages.map((message) => createAnthropicMessagePayload(message, input.clientRequestId, normalizeLightweightRuntimeAttachments(input.attachments ?? [], input.clientRequestId)));
471
+ let finalBody = null;
472
+ for (let index = 0; index < 4; index += 1) {
473
+ const response = await postJsonWithFallbacks({
474
+ baseUrl: runtime.baseUrl,
475
+ pathCandidates: ["v1/messages", "messages"],
476
+ init: {
477
+ method: "POST",
478
+ headers: {
479
+ "content-type": "application/json",
480
+ "anthropic-version": ANTHROPIC_API_VERSION,
481
+ "x-api-key": runtime.apiKey
482
+ },
483
+ body: JSON.stringify({
484
+ model: runtime.model,
485
+ max_tokens: 2048,
486
+ system: LIGHTWEIGHT_SYSTEM_PROMPT,
487
+ messages,
488
+ tools: [
489
+ {
490
+ type: "web_search_20250305",
491
+ name: "web_search",
492
+ max_uses: 5
493
+ }
494
+ ]
495
+ })
496
+ }
497
+ });
498
+ const body = await parseJsonResponse(response);
499
+ if (!response.ok) {
500
+ throw createUpstreamError("ANTHROPIC_LIGHTWEIGHT_FAILED", body, response.status);
501
+ }
502
+ finalBody = body;
503
+ const stopReason = normalizeText(body?.stop_reason);
504
+ const assistantContent = Array.isArray(body?.content) ? body.content : [];
505
+ if (stopReason === "pause_turn") {
506
+ messages = [
507
+ ...messages,
508
+ {
509
+ role: "assistant",
510
+ content: assistantContent
511
+ }
512
+ ];
513
+ continue;
514
+ }
515
+ break;
516
+ }
517
+ const outputText = extractAnthropicOutputText(finalBody?.content);
518
+ if (!outputText) {
519
+ throw new AppError({
520
+ statusCode: 502,
521
+ errorCode: "ANTHROPIC_LIGHTWEIGHT_EMPTY",
522
+ detail: "轻量 Claude Code 没有返回正文"
523
+ });
524
+ }
525
+ return outputText;
526
+ }
527
+ async generateOpenAiResponseStream(document, input, onDelta, onTool) {
528
+ const runtime = await this.readOpenAiRuntimeConfig(input.model?.trim() || null);
529
+ const headers = {
530
+ "content-type": "application/json",
531
+ authorization: `Bearer ${runtime.apiKey}`
532
+ };
533
+ const responsePayload = {
534
+ ...createOpenAiResponsesPayload({
535
+ model: runtime.model,
536
+ messages: document.messages,
537
+ reasoningLevel: input.reasoningLevel ?? null,
538
+ activeClientRequestId: input.clientRequestId,
539
+ attachments: normalizeLightweightRuntimeAttachments(input.attachments ?? [], input.clientRequestId)
540
+ }),
541
+ stream: true
542
+ };
543
+ const response = await postJsonWithFallbacks({
544
+ baseUrl: runtime.baseUrl,
545
+ pathCandidates: ["responses", "v1/responses"],
546
+ init: {
547
+ method: "POST",
548
+ headers,
549
+ body: JSON.stringify(responsePayload)
550
+ }
551
+ });
552
+ if (!response.ok) {
553
+ const body = await parseJsonResponse(response);
554
+ throw createUpstreamError("OPENAI_LIGHTWEIGHT_FAILED", body, response.status);
555
+ }
556
+ const streamedText = await streamOpenAiSseText(response, onDelta, onTool);
557
+ if (streamedText) {
558
+ return streamedText;
559
+ }
560
+ const fallbackResponse = await postJsonWithFallbacks({
561
+ baseUrl: runtime.baseUrl,
562
+ pathCandidates: ["v1/chat/completions", "chat/completions"],
563
+ init: {
564
+ method: "POST",
565
+ headers,
566
+ body: JSON.stringify({
567
+ ...createOpenAiChatPayload({
568
+ model: runtime.model,
569
+ messages: document.messages,
570
+ activeClientRequestId: input.clientRequestId,
571
+ attachments: normalizeLightweightRuntimeAttachments(input.attachments ?? [], input.clientRequestId)
572
+ }),
573
+ stream: true
574
+ })
575
+ }
576
+ });
577
+ if (!fallbackResponse.ok) {
578
+ const fallbackBody = await parseJsonResponse(fallbackResponse);
579
+ throw createUpstreamError("OPENAI_LIGHTWEIGHT_FAILED", fallbackBody, fallbackResponse.status);
580
+ }
581
+ return await streamOpenAiSseText(fallbackResponse, onDelta, onTool);
582
+ }
583
+ async generateAnthropicResponseStream(document, input, onDelta, onTool) {
584
+ const runtime = await this.readAnthropicRuntimeConfig(input.model?.trim() || null);
585
+ const response = await postJsonWithFallbacks({
586
+ baseUrl: runtime.baseUrl,
587
+ pathCandidates: ["v1/messages", "messages"],
588
+ init: {
589
+ method: "POST",
590
+ headers: {
591
+ "content-type": "application/json",
592
+ "anthropic-version": ANTHROPIC_API_VERSION,
593
+ "x-api-key": runtime.apiKey
594
+ },
595
+ body: JSON.stringify({
596
+ model: runtime.model,
597
+ max_tokens: 2048,
598
+ system: LIGHTWEIGHT_SYSTEM_PROMPT,
599
+ messages: document.messages.map((message) => createAnthropicMessagePayload(message, input.clientRequestId, normalizeLightweightRuntimeAttachments(input.attachments ?? [], input.clientRequestId))),
600
+ tools: [
601
+ {
602
+ type: "web_search_20250305",
603
+ name: "web_search",
604
+ max_uses: 5
605
+ }
606
+ ],
607
+ stream: true
608
+ })
609
+ }
610
+ });
611
+ if (!response.ok) {
612
+ const body = await parseJsonResponse(response);
613
+ throw createUpstreamError("ANTHROPIC_LIGHTWEIGHT_FAILED", body, response.status);
614
+ }
615
+ return await streamAnthropicSseText(response, onDelta, onTool);
616
+ }
617
+ async requireSessionDocument(workspaceId, sessionId, userId) {
618
+ const document = await this.readSessionDocument(workspaceId, sessionId);
619
+ if (!document || document.userId !== userId) {
620
+ throw new AppError({
621
+ statusCode: 404,
622
+ errorCode: "AFFAIRS_LIGHTWEIGHT_SESSION_NOT_FOUND",
623
+ detail: "未找到对应的事务轻量会话"
624
+ });
625
+ }
626
+ return document;
627
+ }
628
+ async readSessionDocument(workspaceId, sessionId) {
629
+ return this.readSessionDocumentByPath(this.resolveSessionFilePath(workspaceId, sessionId), sessionId);
630
+ }
631
+ async readSessionDocumentByPath(filePath, expectedSessionId = inferSessionIdFromSessionFilePath(filePath)) {
632
+ for (let attemptIndex = 0; attemptIndex <= LIGHTWEIGHT_SESSION_READ_RETRY_DELAYS_MS.length; attemptIndex += 1) {
633
+ try {
634
+ const raw = await fs.readFile(filePath, "utf8");
635
+ const parsed = JSON.parse(raw);
636
+ if (!parsed || typeof parsed !== "object") {
637
+ return this.readCachedSessionDocument(expectedSessionId);
638
+ }
639
+ if (!parsed.session || !Array.isArray(parsed.messages)) {
640
+ return this.readCachedSessionDocument(expectedSessionId);
641
+ }
642
+ this.cacheSessionDocument(parsed);
643
+ return parsed;
644
+ }
645
+ catch (error) {
646
+ if (error.code === "ENOENT") {
647
+ return null;
648
+ }
649
+ if (!shouldRetrySessionDocumentRead(error) || attemptIndex >= LIGHTWEIGHT_SESSION_READ_RETRY_DELAYS_MS.length) {
650
+ const cached = this.readCachedSessionDocument(expectedSessionId);
651
+ if (cached) {
652
+ return cached;
653
+ }
654
+ throw error;
655
+ }
656
+ await sleep(LIGHTWEIGHT_SESSION_READ_RETRY_DELAYS_MS[attemptIndex]);
657
+ }
658
+ }
659
+ return this.readCachedSessionDocument(expectedSessionId);
660
+ }
661
+ async writeSessionDocument(document) {
662
+ const filePath = document.session.rawStoreRef;
663
+ const tempFilePath = `${filePath}.${process.pid}.${createId()}${LIGHTWEIGHT_SESSION_TMP_FILE_SUFFIX}`;
664
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
665
+ await fs.writeFile(tempFilePath, `${JSON.stringify(document, null, 2)}\n`, "utf8");
666
+ await fs.rename(tempFilePath, filePath);
667
+ this.cacheSessionDocument(document);
668
+ }
669
+ async updateSessionSummary(workspaceId, sessionId, userId, updater, reason) {
670
+ const document = await this.requireSessionDocument(workspaceId, sessionId, userId);
671
+ const nextSession = updater(document.session);
672
+ await this.writeSessionDocument({
673
+ ...document,
674
+ session: nextSession
675
+ });
676
+ this.notifyTeableSessionChanged(userId, `${reason ?? "session_updated"}:${workspaceId}:${sessionId}`);
677
+ return nextSession;
678
+ }
679
+ async waitForSessionIdle(sessionId) {
680
+ const inflight = this.sessionLocks.get(sessionId);
681
+ if (inflight) {
682
+ await inflight;
683
+ }
684
+ }
685
+ cacheSessionDocument(document) {
686
+ const sessionId = document.session.sessionId?.trim();
687
+ if (!sessionId) {
688
+ return;
689
+ }
690
+ this.sessionDocumentCache.set(sessionId, cloneSessionDocument(document));
691
+ }
692
+ notifyTeableSessionChanged(userId, reason) {
693
+ this.teableMirrorSyncNotifier?.(userId, reason);
694
+ }
695
+ readCachedSessionDocument(sessionId) {
696
+ const normalizedSessionId = sessionId?.trim() ?? "";
697
+ if (!normalizedSessionId) {
698
+ return null;
699
+ }
700
+ const cached = this.sessionDocumentCache.get(normalizedSessionId);
701
+ return cached ? cloneSessionDocument(cached) : null;
702
+ }
703
+ async readOpenAiRuntimeConfig(modelOverride) {
704
+ const injectedConfig = await this.readLightweightRuntimeConfigFile();
705
+ const authPath = path.join(os.homedir(), ".codex", "auth.json");
706
+ const configPath = path.join(os.homedir(), ".codex", "config.toml");
707
+ const auth = await readJsonFile(authPath);
708
+ const toml = await safeReadTextFile(configPath);
709
+ const parsed = parseCodexTomlConfig(toml);
710
+ const key = pickFirstText(process.env.CODINGNS_LIGHTWEIGHT_OPENAI_API_KEY, process.env.OPENAI_API_KEY, injectedConfig?.openai?.apiKey, String(auth?.OPENAI_API_KEY ?? ""));
711
+ const baseUrl = normalizeBaseUrl(pickFirstText(process.env.CODINGNS_LIGHTWEIGHT_OPENAI_BASE_URL, injectedConfig?.openai?.baseUrl, process.env.OPENAI_BASE_URL, parsed.baseUrl, "https://api.openai.com/v1") ?? "https://api.openai.com/v1");
712
+ const model = modelOverride
713
+ || pickFirstText(process.env.CODINGNS_LIGHTWEIGHT_OPENAI_MODEL, injectedConfig?.openai?.model, process.env.OPENAI_MODEL, parsed.model, DEFAULT_OPENAI_MODEL)
714
+ || DEFAULT_OPENAI_MODEL;
715
+ if (!key) {
716
+ throw new AppError({
717
+ statusCode: 500,
718
+ errorCode: "OPENAI_LIGHTWEIGHT_AUTH_MISSING",
719
+ detail: `未找到 Codex 轻量会话可用的 API key。优先检查 ~/.codex/auth.json,或在 ${this.getLightweightRuntimeConfigPath()} 写入 openai.apiKey。`
720
+ });
721
+ }
722
+ return {
723
+ apiKey: key,
724
+ baseUrl,
725
+ model
726
+ };
727
+ }
728
+ async readAnthropicRuntimeConfig(modelOverride) {
729
+ const injectedConfig = await this.readLightweightRuntimeConfigFile();
730
+ const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
731
+ const configPath = path.join(os.homedir(), ".claude", "config.json");
732
+ const settings = await readJsonFile(settingsPath);
733
+ const config = await readJsonFile(configPath);
734
+ const env = typeof settings?.env === "object" && settings.env ? settings.env : {};
735
+ const key = pickFirstText(process.env.CODINGNS_LIGHTWEIGHT_ANTHROPIC_API_KEY, process.env.ANTHROPIC_API_KEY, injectedConfig?.anthropic?.apiKey, String(env.ANTHROPIC_AUTH_TOKEN ?? config?.primaryApiKey ?? ""));
736
+ const baseUrl = normalizeBaseUrl(pickFirstText(process.env.CODINGNS_LIGHTWEIGHT_ANTHROPIC_BASE_URL, injectedConfig?.anthropic?.baseUrl, String(env.ANTHROPIC_BASE_URL ?? ""), process.env.ANTHROPIC_BASE_URL, "https://api.anthropic.com") ?? "https://api.anthropic.com");
737
+ const model = modelOverride
738
+ || pickFirstText(process.env.CODINGNS_LIGHTWEIGHT_ANTHROPIC_MODEL, injectedConfig?.anthropic?.model, String(env.ANTHROPIC_MODEL ?? ""), DEFAULT_CLAUDE_MODEL)
739
+ || DEFAULT_CLAUDE_MODEL;
740
+ if (!key) {
741
+ throw new AppError({
742
+ statusCode: 500,
743
+ errorCode: "ANTHROPIC_LIGHTWEIGHT_AUTH_MISSING",
744
+ detail: `未找到 Claude Code 轻量会话可用的 API key。优先检查 ~/.claude/settings.json 或 ~/.claude/config.json,或在 ${this.getLightweightRuntimeConfigPath()} 写入 anthropic.apiKey。`
745
+ });
746
+ }
747
+ return {
748
+ apiKey: key,
749
+ baseUrl,
750
+ model
751
+ };
752
+ }
753
+ resolveWorkspaceDir(workspaceId) {
754
+ return path.join(this.hostDataRootDir, "affairs-lightweight-sessions", workspaceId);
755
+ }
756
+ resolveSessionFilePath(workspaceId, sessionId) {
757
+ return path.join(this.resolveWorkspaceDir(workspaceId), `${sessionId}.json`);
758
+ }
759
+ getLightweightRuntimeConfigPath() {
760
+ return path.join(this.hostDataRootDir, "lightweight-runtime.json");
761
+ }
762
+ async readLightweightRuntimeConfigFile() {
763
+ const configPath = this.getLightweightRuntimeConfigPath();
764
+ const content = await safeReadTextFile(configPath);
765
+ if (!content) {
766
+ return null;
767
+ }
768
+ try {
769
+ const parsed = JSON.parse(content);
770
+ return parsed && typeof parsed === "object" ? parsed : null;
771
+ }
772
+ catch {
773
+ throw new AppError({
774
+ statusCode: 500,
775
+ errorCode: "LIGHTWEIGHT_RUNTIME_CONFIG_INVALID",
776
+ detail: `事务轻量会话配置文件不是合法 JSON:${configPath}`
777
+ });
778
+ }
779
+ }
780
+ }
781
+ function validateLightweightProvider(provider) {
782
+ if (!LIGHTWEIGHT_PROVIDER_IDS.has(provider)) {
783
+ throw new AppError({
784
+ statusCode: 400,
785
+ errorCode: "INVALID_INPUT",
786
+ detail: "事务轻量会话只支持 Codex 和 Claude Code",
787
+ field: "provider"
788
+ });
789
+ }
790
+ }
791
+ function normalizeClientRequestId(value) {
792
+ const normalized = value?.trim();
793
+ return normalized || createId();
794
+ }
795
+ function normalizeOptionalTimestamp(value) {
796
+ const normalized = value?.trim() ?? "";
797
+ if (!normalized) {
798
+ return null;
799
+ }
800
+ const parsed = Date.parse(normalized);
801
+ return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
802
+ }
803
+ function buildDraftTitle(content) {
804
+ const singleLine = content.replace(/\s+/g, " ").trim();
805
+ if (!singleLine) {
806
+ return "新对话";
807
+ }
808
+ return singleLine.length > 24 ? `${singleLine.slice(0, 24)}…` : singleLine;
809
+ }
810
+ function createUserMessage(input) {
811
+ return {
812
+ messageId: `lightweight-user-${input.clientRequestId}`,
813
+ provider: input.provider,
814
+ providerSessionId: input.providerSessionId,
815
+ role: "user",
816
+ kind: "text",
817
+ content: input.content,
818
+ toolCall: null,
819
+ timestamp: input.timestamp,
820
+ attachments: input.attachments ?? [],
821
+ sequence: input.sequence,
822
+ rawRef: `${input.rawStoreRef}#${input.clientRequestId}`
823
+ };
824
+ }
825
+ function createAssistantMessage(input) {
826
+ return {
827
+ messageId: `lightweight-assistant-${createId()}`,
828
+ provider: input.provider,
829
+ providerSessionId: input.providerSessionId,
830
+ role: "assistant",
831
+ kind: "text",
832
+ content: input.content,
833
+ toolCall: null,
834
+ timestamp: input.timestamp,
835
+ sequence: input.sequence,
836
+ rawRef: `${input.rawStoreRef}#assistant-${input.sequence}`
837
+ };
838
+ }
839
+ function createToolLifecycleMessage(input) {
840
+ const content = normalizeText(input.event.detail)
841
+ || normalizeText(input.event.output)
842
+ || normalizeText(input.event.input)
843
+ || input.event.toolName;
844
+ return {
845
+ messageId: `lightweight-tool-${input.event.toolCallId}`,
846
+ provider: input.provider,
847
+ providerSessionId: input.providerSessionId,
848
+ role: "tool",
849
+ kind: input.event.status === "running" ? "tool_call" : "tool_result",
850
+ content,
851
+ toolCall: {
852
+ callId: input.event.toolCallId,
853
+ name: input.event.toolName,
854
+ input: input.event.input ?? "",
855
+ output: input.event.output,
856
+ error: input.event.status === "failed"
857
+ ? (normalizeText(input.event.detail) || normalizeText(input.event.output) || null)
858
+ : null,
859
+ status: input.event.status
860
+ },
861
+ timestamp: input.timestamp,
862
+ sequence: input.sequence,
863
+ rawRef: `${input.rawStoreRef}#tool-${input.event.toolCallId}`
864
+ };
865
+ }
866
+ function upsertToolLifecycleMessage(input) {
867
+ const timestamp = input.observedAt ?? new Date().toISOString();
868
+ const existingIndex = input.document.messages.findIndex((message) => {
869
+ if (message.role !== "tool" || !message.toolCall) {
870
+ return false;
871
+ }
872
+ return message.toolCall.callId === input.event.toolCallId;
873
+ });
874
+ if (existingIndex >= 0) {
875
+ const existing = input.document.messages[existingIndex];
876
+ const nextMessage = createToolLifecycleMessage({
877
+ provider: input.document.session.provider,
878
+ providerSessionId: input.document.session.providerSessionId,
879
+ timestamp,
880
+ rawStoreRef: input.document.session.rawStoreRef,
881
+ sequence: existing.sequence,
882
+ event: input.event
883
+ });
884
+ const nextMessages = [...input.document.messages];
885
+ nextMessages[existingIndex] = {
886
+ ...nextMessage,
887
+ timestamp: existing.timestamp,
888
+ sequence: existing.sequence,
889
+ rawRef: existing.rawRef,
890
+ messageId: existing.messageId
891
+ };
892
+ return {
893
+ ...input.document,
894
+ messages: nextMessages,
895
+ session: {
896
+ ...input.document.session,
897
+ updatedAt: timestamp,
898
+ lastEventAt: timestamp,
899
+ messageCount: nextMessages.length
900
+ }
901
+ };
902
+ }
903
+ const assistantIndex = input.document.messages.findIndex((message) => message.role === "assistant");
904
+ const insertAt = assistantIndex >= 0 ? assistantIndex : input.document.messages.length;
905
+ const sequence = insertAt > 0
906
+ ? input.document.messages[insertAt - 1].sequence + 1
907
+ : 1;
908
+ const nextMessage = createToolLifecycleMessage({
909
+ provider: input.document.session.provider,
910
+ providerSessionId: input.document.session.providerSessionId,
911
+ timestamp,
912
+ rawStoreRef: input.document.session.rawStoreRef,
913
+ sequence,
914
+ event: input.event
915
+ });
916
+ const nextMessages = [
917
+ ...input.document.messages.slice(0, insertAt),
918
+ nextMessage,
919
+ ...input.document.messages.slice(insertAt).map((message) => ({
920
+ ...message,
921
+ sequence: message.sequence + 1,
922
+ rawRef: message.role === "assistant"
923
+ ? `${input.document.session.rawStoreRef}#assistant-${message.sequence + 1}`
924
+ : message.rawRef
925
+ }))
926
+ ];
927
+ return {
928
+ ...input.document,
929
+ messages: nextMessages,
930
+ session: {
931
+ ...input.document.session,
932
+ updatedAt: timestamp,
933
+ lastEventAt: timestamp,
934
+ messageCount: nextMessages.length
935
+ }
936
+ };
937
+ }
938
+ function normalizeOpenAiReasoning(reasoningLevel) {
939
+ const normalized = reasoningLevel?.trim().toLowerCase();
940
+ if (normalized === "low" || normalized === "medium" || normalized === "high") {
941
+ return { effort: normalized };
942
+ }
943
+ if (normalized === "xhigh") {
944
+ return { effort: "high" };
945
+ }
946
+ return { effort: "medium" };
947
+ }
948
+ function createOpenAiResponsesPayload(input) {
949
+ return {
950
+ model: input.model,
951
+ reasoning: normalizeOpenAiReasoning(input.reasoningLevel),
952
+ tools: [
953
+ {
954
+ type: "web_search",
955
+ user_location: {
956
+ type: "approximate",
957
+ country: "US"
958
+ }
959
+ }
960
+ ],
961
+ tool_choice: "auto",
962
+ include: ["web_search_call.action.sources"],
963
+ input: [
964
+ {
965
+ role: "system",
966
+ content: LIGHTWEIGHT_SYSTEM_PROMPT
967
+ },
968
+ ...input.messages.map((message) => ({
969
+ role: message.role,
970
+ content: createOpenAiResponsesMessageContent(message, input.activeClientRequestId, input.attachments ?? [])
971
+ }))
972
+ ]
973
+ };
974
+ }
975
+ function createOpenAiChatPayload(input) {
976
+ return {
977
+ model: input.model,
978
+ messages: [
979
+ {
980
+ role: "system",
981
+ content: LIGHTWEIGHT_SYSTEM_PROMPT
982
+ },
983
+ ...input.messages.map((message) => ({
984
+ role: message.role,
985
+ content: createOpenAiChatMessageContent(message, input.activeClientRequestId, input.attachments ?? [])
986
+ }))
987
+ ],
988
+ temperature: 0.2
989
+ };
990
+ }
991
+ function normalizeLightweightRuntimeAttachments(attachments, clientRequestId) {
992
+ return attachments.map((attachment, index) => {
993
+ const kind = attachment.kind === "image" ? "image" : "file";
994
+ return {
995
+ id: attachment.id?.trim() || `lightweight-attachment-${clientRequestId}-${index + 1}`,
996
+ kind,
997
+ fileName: attachment.fileName.trim(),
998
+ mimeType: attachment.mimeType.trim(),
999
+ fileSize: Number(attachment.fileSize),
1000
+ contentBase64: attachment.contentBase64.trim()
1001
+ };
1002
+ }).filter((attachment) => (attachment.fileName.length > 0
1003
+ && attachment.mimeType.length > 0
1004
+ && attachment.contentBase64.length > 0
1005
+ && Number.isFinite(attachment.fileSize)
1006
+ && attachment.fileSize > 0));
1007
+ }
1008
+ function normalizeLightweightMessageAttachments(attachments, clientRequestId) {
1009
+ return normalizeLightweightRuntimeAttachments(attachments, clientRequestId).map((attachment) => ({
1010
+ id: attachment.id,
1011
+ kind: attachment.kind,
1012
+ fileName: attachment.fileName,
1013
+ mimeType: attachment.mimeType,
1014
+ fileSize: attachment.fileSize
1015
+ }));
1016
+ }
1017
+ function shouldAttachRuntimePayloadToMessage(message, activeClientRequestId, attachments) {
1018
+ return message.role === "user"
1019
+ && attachments.length > 0
1020
+ && Boolean(activeClientRequestId?.trim())
1021
+ && message.rawRef.includes(activeClientRequestId.trim());
1022
+ }
1023
+ function createOpenAiResponsesMessageContent(message, activeClientRequestId, attachments) {
1024
+ if (!shouldAttachRuntimePayloadToMessage(message, activeClientRequestId, attachments)) {
1025
+ return message.content;
1026
+ }
1027
+ return [
1028
+ { type: "input_text", text: message.content.trim() || "请根据附件回答。" },
1029
+ ...attachments.flatMap((attachment) => createOpenAiResponsesAttachmentBlocks(attachment))
1030
+ ];
1031
+ }
1032
+ function createOpenAiChatMessageContent(message, activeClientRequestId, attachments) {
1033
+ if (!shouldAttachRuntimePayloadToMessage(message, activeClientRequestId, attachments)) {
1034
+ return message.content;
1035
+ }
1036
+ return [
1037
+ { type: "text", text: message.content.trim() || "请根据附件回答。" },
1038
+ ...attachments.flatMap((attachment) => createOpenAiChatAttachmentBlocks(attachment))
1039
+ ];
1040
+ }
1041
+ function createAnthropicMessagePayload(message, activeClientRequestId, attachments) {
1042
+ if (!shouldAttachRuntimePayloadToMessage(message, activeClientRequestId, attachments)) {
1043
+ return {
1044
+ role: message.role,
1045
+ content: message.content
1046
+ };
1047
+ }
1048
+ return {
1049
+ role: message.role,
1050
+ content: [
1051
+ { type: "text", text: message.content.trim() || "请根据附件回答。" },
1052
+ ...attachments.flatMap((attachment) => createAnthropicAttachmentBlocks(attachment))
1053
+ ]
1054
+ };
1055
+ }
1056
+ function createOpenAiResponsesAttachmentBlocks(attachment) {
1057
+ if (attachment.kind === "image") {
1058
+ return [{
1059
+ type: "input_image",
1060
+ image_url: buildAttachmentDataUrl(attachment)
1061
+ }];
1062
+ }
1063
+ return [{ type: "input_text", text: buildAttachmentTextBlock(attachment) }];
1064
+ }
1065
+ function createOpenAiChatAttachmentBlocks(attachment) {
1066
+ if (attachment.kind === "image") {
1067
+ return [{
1068
+ type: "image_url",
1069
+ image_url: { url: buildAttachmentDataUrl(attachment) }
1070
+ }];
1071
+ }
1072
+ return [{ type: "text", text: buildAttachmentTextBlock(attachment) }];
1073
+ }
1074
+ function createAnthropicAttachmentBlocks(attachment) {
1075
+ if (attachment.kind === "image") {
1076
+ return [{
1077
+ type: "image",
1078
+ source: {
1079
+ type: "base64",
1080
+ media_type: attachment.mimeType,
1081
+ data: attachment.contentBase64
1082
+ }
1083
+ }];
1084
+ }
1085
+ return [{ type: "text", text: buildAttachmentTextBlock(attachment) }];
1086
+ }
1087
+ function buildAttachmentDataUrl(attachment) {
1088
+ return `data:${attachment.mimeType};base64,${attachment.contentBase64}`;
1089
+ }
1090
+ function buildAttachmentTextBlock(attachment) {
1091
+ const decoded = decodeTextAttachment(attachment);
1092
+ const header = [
1093
+ `附件文件:${attachment.fileName}`,
1094
+ `类型:${attachment.mimeType}`,
1095
+ `大小:${attachment.fileSize} bytes`
1096
+ ].join("\n");
1097
+ if (!decoded) {
1098
+ return `${header}\n内容:这个文件不是可直接读取的文本格式。请根据文件名、类型和用户问题判断;如果必须读取原始内容,请建议切换到 Agent 会话。`;
1099
+ }
1100
+ const preview = decoded.length > 20_000 ? `${decoded.slice(0, 20_000)}\n...(内容过长,已截断)` : decoded;
1101
+ return `${header}\n内容:\n${preview}`;
1102
+ }
1103
+ function decodeTextAttachment(attachment) {
1104
+ const mimeType = attachment.mimeType.toLowerCase();
1105
+ const fileName = attachment.fileName.toLowerCase();
1106
+ const looksText = mimeType.startsWith("text/")
1107
+ || ["application/json", "application/xml", "application/javascript", "application/typescript", "application/x-yaml"].includes(mimeType)
1108
+ || /\.(txt|md|csv|json|xml|yaml|yml|log|ts|tsx|js|jsx|css|html|sql)$/i.test(fileName);
1109
+ if (!looksText) {
1110
+ return null;
1111
+ }
1112
+ try {
1113
+ return Buffer.from(attachment.contentBase64, "base64").toString("utf8");
1114
+ }
1115
+ catch {
1116
+ return null;
1117
+ }
1118
+ }
1119
+ function extractOpenAiResponseText(body) {
1120
+ return normalizeText(body?.output_text)
1121
+ ?? extractOpenAiOutputText(body?.output)
1122
+ ?? extractOpenAiChoiceText(body);
1123
+ }
1124
+ function extractOpenAiOutputText(output) {
1125
+ if (!Array.isArray(output)) {
1126
+ return null;
1127
+ }
1128
+ const segments = [];
1129
+ for (const item of output) {
1130
+ if (!item || typeof item !== "object") {
1131
+ continue;
1132
+ }
1133
+ const content = Array.isArray(item.content) ? item.content : [];
1134
+ for (const part of content) {
1135
+ const text = normalizeText(part?.text);
1136
+ if (text) {
1137
+ segments.push(text);
1138
+ }
1139
+ }
1140
+ }
1141
+ return segments.length > 0 ? segments.join("\n\n") : null;
1142
+ }
1143
+ function extractOpenAiChoiceText(body) {
1144
+ const rawContent = body?.choices?.[0]?.message?.content;
1145
+ if (typeof rawContent === "string") {
1146
+ return normalizeText(rawContent);
1147
+ }
1148
+ if (!Array.isArray(rawContent)) {
1149
+ return null;
1150
+ }
1151
+ const segments = rawContent
1152
+ .map((item) => {
1153
+ if (typeof item === "string") {
1154
+ return item;
1155
+ }
1156
+ return normalizeText(item?.text);
1157
+ })
1158
+ .filter((item) => Boolean(item));
1159
+ return segments.length > 0 ? segments.join("\n\n") : null;
1160
+ }
1161
+ function extractAnthropicOutputText(content) {
1162
+ if (!Array.isArray(content)) {
1163
+ return null;
1164
+ }
1165
+ const segments = content
1166
+ .map((item) => normalizeText(item?.text))
1167
+ .filter((item) => Boolean(item));
1168
+ return segments.length > 0 ? segments.join("\n\n") : null;
1169
+ }
1170
+ function normalizeText(value) {
1171
+ const normalized = value?.trim();
1172
+ return normalized ? normalized : null;
1173
+ }
1174
+ function pickFirstText(...values) {
1175
+ for (const value of values) {
1176
+ const normalized = normalizeText(value);
1177
+ if (normalized) {
1178
+ return normalized;
1179
+ }
1180
+ }
1181
+ return null;
1182
+ }
1183
+ function normalizeBaseUrl(value) {
1184
+ return value.replace(/\/+$/, "");
1185
+ }
1186
+ async function streamOpenAiSseText(response, onDelta, onTool) {
1187
+ let accumulated = "";
1188
+ await consumeSseResponse(response, async ({ event, data }) => {
1189
+ if (!data || data === "[DONE]") {
1190
+ return;
1191
+ }
1192
+ let payload = null;
1193
+ try {
1194
+ payload = JSON.parse(data);
1195
+ }
1196
+ catch {
1197
+ return;
1198
+ }
1199
+ const toolEvent = extractOpenAiSseToolEvent(event, payload);
1200
+ if (toolEvent) {
1201
+ await onTool?.(toolEvent);
1202
+ }
1203
+ const chunks = extractOpenAiSseDeltaChunks(payload);
1204
+ for (const chunk of chunks) {
1205
+ if (!chunk) {
1206
+ continue;
1207
+ }
1208
+ accumulated += chunk;
1209
+ await onDelta(chunk);
1210
+ }
1211
+ });
1212
+ return normalizeText(accumulated);
1213
+ }
1214
+ async function streamAnthropicSseText(response, onDelta, onTool) {
1215
+ let accumulated = "";
1216
+ await consumeSseResponse(response, async ({ event, data }) => {
1217
+ if (!data) {
1218
+ return;
1219
+ }
1220
+ let payload = null;
1221
+ try {
1222
+ payload = JSON.parse(data);
1223
+ }
1224
+ catch {
1225
+ return;
1226
+ }
1227
+ const eventType = event || payload?.type;
1228
+ const toolEvent = extractAnthropicSseToolEvent(eventType, payload);
1229
+ if (toolEvent) {
1230
+ await onTool?.(toolEvent);
1231
+ }
1232
+ if (eventType === "content_block_delta" && payload?.delta?.type === "text_delta") {
1233
+ const chunk = normalizeText(payload?.delta?.text);
1234
+ if (chunk) {
1235
+ accumulated += chunk;
1236
+ await onDelta(chunk);
1237
+ }
1238
+ return;
1239
+ }
1240
+ if (eventType === "content_block_start" && payload?.content_block?.type === "text") {
1241
+ const chunk = normalizeText(payload?.content_block?.text);
1242
+ if (chunk) {
1243
+ accumulated += chunk;
1244
+ await onDelta(chunk);
1245
+ }
1246
+ }
1247
+ });
1248
+ return normalizeText(accumulated);
1249
+ }
1250
+ async function consumeSseResponse(response, onEvent) {
1251
+ const reader = response.body?.getReader();
1252
+ if (!reader) {
1253
+ return;
1254
+ }
1255
+ const decoder = new TextDecoder();
1256
+ let buffer = "";
1257
+ let currentEvent = "";
1258
+ let currentDataLines = [];
1259
+ const flushEvent = async () => {
1260
+ if (!currentEvent && currentDataLines.length === 0) {
1261
+ return;
1262
+ }
1263
+ const payload = {
1264
+ event: currentEvent,
1265
+ data: currentDataLines.join("\n")
1266
+ };
1267
+ currentEvent = "";
1268
+ currentDataLines = [];
1269
+ await onEvent(payload);
1270
+ };
1271
+ while (true) {
1272
+ const next = await reader.read();
1273
+ buffer += decoder.decode(next.value ?? new Uint8Array(), { stream: !next.done });
1274
+ while (true) {
1275
+ const newlineIndex = buffer.indexOf("\n");
1276
+ if (newlineIndex < 0) {
1277
+ break;
1278
+ }
1279
+ const rawLine = buffer.slice(0, newlineIndex).replace(/\r$/, "");
1280
+ buffer = buffer.slice(newlineIndex + 1);
1281
+ if (!rawLine) {
1282
+ await flushEvent();
1283
+ continue;
1284
+ }
1285
+ if (rawLine.startsWith(":")) {
1286
+ continue;
1287
+ }
1288
+ if (rawLine.startsWith("event:")) {
1289
+ currentEvent = rawLine.slice("event:".length).trim();
1290
+ continue;
1291
+ }
1292
+ if (rawLine.startsWith("data:")) {
1293
+ currentDataLines.push(rawLine.slice("data:".length).trimStart());
1294
+ }
1295
+ }
1296
+ if (next.done) {
1297
+ break;
1298
+ }
1299
+ }
1300
+ if (buffer.trim()) {
1301
+ const trailingLine = buffer.replace(/\r$/, "");
1302
+ if (trailingLine.startsWith("data:")) {
1303
+ currentDataLines.push(trailingLine.slice("data:".length).trimStart());
1304
+ }
1305
+ }
1306
+ await flushEvent();
1307
+ }
1308
+ function extractOpenAiSseDeltaChunks(payload) {
1309
+ const chunks = [];
1310
+ const responseDelta = normalizeText(payload?.delta);
1311
+ if (responseDelta) {
1312
+ chunks.push(responseDelta);
1313
+ }
1314
+ const outputTextDelta = normalizeText(payload?.text);
1315
+ if (payload?.type === "response.output_text.delta" && outputTextDelta) {
1316
+ chunks.push(outputTextDelta);
1317
+ }
1318
+ const chatDelta = payload?.choices?.[0]?.delta?.content;
1319
+ if (typeof chatDelta === "string" && chatDelta.trim().length > 0) {
1320
+ chunks.push(chatDelta);
1321
+ }
1322
+ return chunks;
1323
+ }
1324
+ function extractOpenAiSseToolEvent(eventName, payload) {
1325
+ const payloadType = normalizeText(payload?.type) ?? "";
1326
+ const resolvedEvent = normalizeText(eventName) ?? payloadType;
1327
+ const isDirectWebSearchEvent = resolvedEvent.includes("web_search_call");
1328
+ const isOutputItemWebSearchEvent = resolvedEvent === "response.output_item.done"
1329
+ && normalizeText(payload?.item?.type) === "web_search_call";
1330
+ const isOutputItemAddedWebSearchEvent = resolvedEvent === "response.output_item.added"
1331
+ && normalizeText(payload?.item?.type) === "web_search_call";
1332
+ if (!isDirectWebSearchEvent && !isOutputItemWebSearchEvent && !isOutputItemAddedWebSearchEvent) {
1333
+ return null;
1334
+ }
1335
+ const toolCallId = normalizeText(payload?.item_id)
1336
+ || normalizeText(payload?.item?.id)
1337
+ || normalizeText(payload?.call_id)
1338
+ || normalizeText(payload?.id)
1339
+ || "web_search";
1340
+ const status = isOutputItemWebSearchEvent
1341
+ ? "completed"
1342
+ : resolvedEvent.endsWith(".completed")
1343
+ ? "completed"
1344
+ : resolvedEvent.endsWith(".failed")
1345
+ ? "failed"
1346
+ : "running";
1347
+ const sources = readWebSearchSources(payload);
1348
+ const sourceCount = sources.length;
1349
+ const input = readWebSearchQuery(payload);
1350
+ const detail = status === "completed"
1351
+ ? (sourceCount > 0 ? `联网搜索完成,找到 ${sourceCount} 个来源` : "联网搜索完成")
1352
+ : status === "failed"
1353
+ ? normalizeText(payload?.error?.message) || "联网搜索失败"
1354
+ : resolvedEvent.endsWith(".searching")
1355
+ ? "正在联网搜索"
1356
+ : "正在准备联网搜索";
1357
+ return {
1358
+ type: "tool",
1359
+ toolCallId,
1360
+ toolName: "web_search",
1361
+ status,
1362
+ detail,
1363
+ input,
1364
+ output: status === "completed"
1365
+ ? JSON.stringify({
1366
+ detail,
1367
+ query: input,
1368
+ sources
1369
+ }, null, 2)
1370
+ : status === "failed"
1371
+ ? detail
1372
+ : null
1373
+ };
1374
+ }
1375
+ function extractAnthropicSseToolEvent(eventType, payload) {
1376
+ const block = payload?.content_block;
1377
+ const delta = payload?.delta;
1378
+ const blockType = normalizeText(block?.type) ?? normalizeText(delta?.type) ?? "";
1379
+ const toolName = normalizeText(block?.name)
1380
+ || normalizeText(payload?.name)
1381
+ || normalizeText(delta?.name)
1382
+ || (blockType.includes("web_search") ? "web_search" : null);
1383
+ if (toolName !== "web_search") {
1384
+ return null;
1385
+ }
1386
+ const status = eventType === "content_block_stop" || eventType === "message_stop"
1387
+ ? "completed"
1388
+ : eventType === "error"
1389
+ ? "failed"
1390
+ : "running";
1391
+ const input = readWebSearchQuery(payload);
1392
+ const sources = readWebSearchSources(payload);
1393
+ const detail = status === "completed"
1394
+ ? (sources.length > 0 ? `联网搜索完成,找到 ${sources.length} 个来源` : "联网搜索完成")
1395
+ : status === "failed"
1396
+ ? normalizeText(payload?.error?.message) || "联网搜索失败"
1397
+ : "正在联网搜索";
1398
+ return {
1399
+ type: "tool",
1400
+ toolCallId: normalizeText(block?.id) || normalizeText(payload?.id) || normalizeText(delta?.id) || "web_search",
1401
+ toolName,
1402
+ status,
1403
+ detail,
1404
+ input,
1405
+ output: status === "completed"
1406
+ ? JSON.stringify({
1407
+ detail,
1408
+ query: input,
1409
+ sources
1410
+ }, null, 2)
1411
+ : status === "failed"
1412
+ ? detail
1413
+ : null
1414
+ };
1415
+ }
1416
+ function readSourceCount(payload) {
1417
+ return readWebSearchSources(payload).length;
1418
+ }
1419
+ function readWebSearchQuery(payload) {
1420
+ return pickFirstText(payload?.action?.query, payload?.action?.search_query, payload?.item?.action?.query, payload?.item?.action?.search_query, payload?.item?.query, payload?.query, payload?.search_query, payload?.input, payload?.arguments?.query, payload?.arguments?.search_query, payload?.content_block?.input?.query, payload?.content_block?.input?.search_query, payload?.delta?.partial_json, payload?.result?.query, payload?.web_search?.query);
1421
+ }
1422
+ function flattenWebSearchSourceCandidates(payload) {
1423
+ const candidates = [
1424
+ payload?.action?.sources,
1425
+ payload?.item?.action?.sources,
1426
+ payload?.item?.sources,
1427
+ payload?.sources,
1428
+ payload?.result?.sources,
1429
+ payload?.web_search?.sources,
1430
+ payload?.content_block?.results,
1431
+ payload?.content_block?.sources,
1432
+ payload?.results
1433
+ ];
1434
+ for (const candidate of candidates) {
1435
+ if (Array.isArray(candidate) && candidate.length > 0) {
1436
+ return candidate;
1437
+ }
1438
+ }
1439
+ return [];
1440
+ }
1441
+ function readWebSearchSources(payload) {
1442
+ return flattenWebSearchSourceCandidates(payload)
1443
+ .map((item) => ({
1444
+ title: pickFirstText(item?.title, item?.name, item?.text),
1445
+ url: pickFirstText(item?.url, item?.link, item?.uri)
1446
+ }))
1447
+ .filter((item) => item.title || item.url)
1448
+ .slice(0, 8);
1449
+ }
1450
+ async function safeReadTextFile(filePath) {
1451
+ try {
1452
+ return await fs.readFile(filePath, "utf8");
1453
+ }
1454
+ catch (error) {
1455
+ if (error.code === "ENOENT") {
1456
+ return null;
1457
+ }
1458
+ throw error;
1459
+ }
1460
+ }
1461
+ async function readJsonFile(filePath) {
1462
+ const content = await safeReadTextFile(filePath);
1463
+ if (!content) {
1464
+ return {};
1465
+ }
1466
+ return JSON.parse(content);
1467
+ }
1468
+ function parseCodexTomlConfig(content) {
1469
+ if (!content) {
1470
+ return { model: null, baseUrl: null };
1471
+ }
1472
+ const model = matchTomlString(content, /^model\s*=\s*"([^"]+)"/m);
1473
+ const providerId = matchTomlString(content, /^model_provider\s*=\s*"([^"]+)"/m);
1474
+ if (!providerId) {
1475
+ return { model, baseUrl: null };
1476
+ }
1477
+ const marker = `[model_providers.${JSON.stringify(providerId).slice(1, -1)}]`;
1478
+ const sectionStart = content.indexOf(marker);
1479
+ if (sectionStart < 0) {
1480
+ return { model, baseUrl: null };
1481
+ }
1482
+ const nextSection = content.indexOf("\n[", sectionStart + marker.length);
1483
+ const section = nextSection >= 0 ? content.slice(sectionStart, nextSection) : content.slice(sectionStart);
1484
+ const baseUrl = matchTomlString(section, /^base_url\s*=\s*"([^"]+)"/m);
1485
+ return { model, baseUrl };
1486
+ }
1487
+ function matchTomlString(content, pattern) {
1488
+ const matched = content.match(pattern);
1489
+ return matched?.[1]?.trim() || null;
1490
+ }
1491
+ async function safeReadDir(dirPath) {
1492
+ try {
1493
+ return await fs.readdir(dirPath, { withFileTypes: true });
1494
+ }
1495
+ catch (error) {
1496
+ if (error.code === "ENOENT") {
1497
+ return [];
1498
+ }
1499
+ throw error;
1500
+ }
1501
+ }
1502
+ async function postJsonWithFallbacks(input) {
1503
+ let lastResponse = null;
1504
+ for (const candidate of input.pathCandidates) {
1505
+ const url = buildRequestUrl(input.baseUrl, candidate);
1506
+ const response = await fetch(url, input.init);
1507
+ if (response.status !== 404) {
1508
+ return response;
1509
+ }
1510
+ lastResponse = response;
1511
+ }
1512
+ if (lastResponse) {
1513
+ return lastResponse;
1514
+ }
1515
+ throw new AppError({
1516
+ statusCode: 502,
1517
+ errorCode: "LIGHTWEIGHT_RUNTIME_UNREACHABLE",
1518
+ detail: "轻量会话上游地址不可达"
1519
+ });
1520
+ }
1521
+ function buildRequestUrl(baseUrl, candidate) {
1522
+ const normalizedBase = normalizeBaseUrl(baseUrl);
1523
+ const normalizedPath = candidate.replace(/^\/+/, "");
1524
+ return `${normalizedBase}/${normalizedPath}`;
1525
+ }
1526
+ function inferSessionIdFromSessionFilePath(filePath) {
1527
+ const baseName = path.basename(filePath);
1528
+ if (!baseName.endsWith(".json")) {
1529
+ return null;
1530
+ }
1531
+ const sessionId = baseName.slice(0, -".json".length).trim();
1532
+ return sessionId || null;
1533
+ }
1534
+ function cloneSessionDocument(document) {
1535
+ return {
1536
+ ...document,
1537
+ session: {
1538
+ ...document.session
1539
+ },
1540
+ messages: document.messages.map((message) => ({
1541
+ ...message,
1542
+ toolCall: message.toolCall
1543
+ ? {
1544
+ ...message.toolCall
1545
+ }
1546
+ : null
1547
+ }))
1548
+ };
1549
+ }
1550
+ function shouldRetrySessionDocumentRead(error) {
1551
+ if (!(error instanceof Error)) {
1552
+ return false;
1553
+ }
1554
+ return error instanceof SyntaxError || /Unexpected end of JSON input/i.test(error.message);
1555
+ }
1556
+ async function sleep(timeoutMs) {
1557
+ await new Promise((resolve) => {
1558
+ setTimeout(resolve, timeoutMs);
1559
+ });
1560
+ }
1561
+ async function parseJsonResponse(response) {
1562
+ const text = await response.text();
1563
+ if (!text.trim()) {
1564
+ return null;
1565
+ }
1566
+ try {
1567
+ return JSON.parse(text);
1568
+ }
1569
+ catch {
1570
+ return { raw: text };
1571
+ }
1572
+ }
1573
+ function createUpstreamError(code, body, status) {
1574
+ return new AppError({
1575
+ statusCode: 502,
1576
+ errorCode: code,
1577
+ detail: normalizeText(body?.error?.message)
1578
+ || normalizeText(body?.error?.detail)
1579
+ || normalizeText(body?.detail)
1580
+ || normalizeText(body?.raw)
1581
+ || `上游轻量会话接口返回 ${status}`
1582
+ });
1583
+ }
1584
+ function getErrorMessage(error) {
1585
+ if (error instanceof AppError) {
1586
+ return error.message;
1587
+ }
1588
+ if (error instanceof Error) {
1589
+ return error.message;
1590
+ }
1591
+ return "未知错误";
1592
+ }
1593
+ //# sourceMappingURL=affairs-lightweight-session-service.js.map