@jingyi0605/codingns 0.9.0 → 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 (224) hide show
  1. package/dist/public/assets/{AdaptiveButlerPage-B17QiMyT.js → AdaptiveButlerPage-kkJDsnCO.js} +2 -2
  2. package/dist/public/assets/{App-CFBwDUNA.js → App-DrNI9lWA.js} +6 -6
  3. package/dist/public/assets/{BootstrapPage-W5wU3BPh.js → BootstrapPage-QgVH5Mps.js} +1 -1
  4. package/dist/public/assets/{ConversationPage-DQLX1bUh.js → ConversationPage-DVk8VfIj.js} +1 -1
  5. package/dist/public/assets/{DesktopDetachPreviewPage-DTPeuAW-.js → DesktopDetachPreviewPage-BhfP0TpH.js} +1 -1
  6. package/dist/public/assets/{DesktopModal-6ii53_Y9.js → DesktopModal-DRmDrv0S.js} +1 -1
  7. package/dist/public/assets/DesktopWindowPage-DNbJXnSs.js +2 -0
  8. package/dist/public/assets/FileContextPanel---fLO4ve.js +1 -0
  9. package/dist/public/assets/GitSidebar-sXUE0TqT.js +6 -0
  10. package/dist/public/assets/MobileCreateSessionSheet-BftZ5pvb.js +1 -0
  11. package/dist/public/assets/{MobileSheet-opTWyRe1.js → MobileSheet-nw5SCa3N.js} +1 -1
  12. package/dist/public/assets/{MobileTopHeaderFrame-BbNON3Y4.js → MobileTopHeaderFrame-DH_D02Wy.js} +1 -1
  13. package/dist/public/assets/{MobileWorkspaceSwitcherHeader-BZEzPeMj.js → MobileWorkspaceSwitcherHeader-2K406G5p.js} +1 -1
  14. package/dist/public/assets/{PluginAccessOverview-mQDmAljp.js → PluginAccessOverview-BVJihw3D.js} +1 -1
  15. package/dist/public/assets/{PluginContainerPage-CcxUJpM4.js → PluginContainerPage-CR4vStvr.js} +1 -1
  16. package/dist/public/assets/{PluginDetailPage-D5--ACIt.js → PluginDetailPage-CrMX0Mnm.js} +1 -1
  17. package/dist/public/assets/{PluginsListPage-D_oJxYXT.js → PluginsListPage-FtIL71Yg.js} +1 -1
  18. package/dist/public/assets/{RelayConnectEntryPage-DROxpnkv.js → RelayConnectEntryPage-Bt1apX53.js} +1 -1
  19. package/dist/public/assets/{ServerSettingsModal-CUUOPqSe.js → ServerSettingsModal-D-guzPrI.js} +1 -1
  20. package/dist/public/assets/{SessionIndexPage-C2Jxh6Gp.js → SessionIndexPage-CX2FppcJ.js} +1 -1
  21. package/dist/public/assets/SettingsPage-BI2Olcvr.js +2 -0
  22. package/dist/public/assets/TerminalManagerPanel-B5MKGPy-.js +1 -0
  23. package/dist/public/assets/{TerminalPage-CwWyFDj8.js → TerminalPage-C2dTNGHK.js} +1 -1
  24. package/dist/public/assets/{TerminalRuntimeFallbackModal-CSVVbO8r.js → TerminalRuntimeFallbackModal-DAqOxFD8.js} +1 -1
  25. package/dist/public/assets/{ToolFilesPage-QBEY8oCf.js → ToolFilesPage-IsNwyE6T.js} +1 -1
  26. package/dist/public/assets/{ToolGitPage-BKoZ2l9v.js → ToolGitPage-BK1JBERN.js} +1 -1
  27. package/dist/public/assets/{ToolProcessesPage-BOH0ib4G.js → ToolProcessesPage-DwTYUQCK.js} +1 -1
  28. package/dist/public/assets/{ToolsHomePage-BcMZ3BCQ.js → ToolsHomePage-BLOy7lPg.js} +1 -1
  29. package/dist/public/assets/{WorkbenchLandingPage-B5zoppEl.js → WorkbenchLandingPage-CqZKR6EA.js} +1 -1
  30. package/dist/public/assets/WorkbenchLayout-CJHQtwuL.js +1022 -0
  31. package/dist/public/assets/{WorkbenchModal-NGmPgqaE.js → WorkbenchModal-BM-OeW-b.js} +1 -1
  32. package/dist/public/assets/WorkbenchShellRoute-2bKI6Q9k.js +1 -0
  33. package/dist/public/assets/WorkbenchShellRoute-BjuZD101.css +1 -0
  34. package/dist/public/assets/WorkspaceDebugDetailPage-BMsEN5iG.js +1 -0
  35. package/dist/public/assets/WorkspaceDetailPage-5H9Gosx2.js +1 -0
  36. package/dist/public/assets/WorkspaceHomePage-DQiXKgiP.js +1 -0
  37. package/dist/public/assets/{client-runtime-manager-DXbI9K1K.js → client-runtime-manager-CgPJq21V.js} +1 -1
  38. package/dist/public/assets/index-BARqMVSw.css +1 -0
  39. package/dist/public/assets/index-BUoNjVrY.js +50 -0
  40. package/dist/public/assets/{login-direct-candidate-resolver-DkKyFtQJ.js → login-direct-candidate-resolver-CGaxAXV8.js} +1 -1
  41. package/dist/public/assets/{plugin-permission-copy-CzN269Bk.js → plugin-permission-copy-BR9gWy8b.js} +1 -1
  42. package/dist/public/assets/{plugins-api-Bv9DHpLF.js → plugins-api-CdCsrG2e.js} +1 -1
  43. package/dist/public/assets/{preferences-service-D2ISL2Zz.js → preferences-service-lOhnlxzP.js} +1 -1
  44. package/dist/public/assets/{relay-entry-Bg0OisQy.js → relay-entry-CQpxTS8y.js} +1 -1
  45. package/dist/public/assets/{terminal-runtime-meta-C8t-CIDF.js → terminal-runtime-meta-oteTx66X.js} +1 -1
  46. package/dist/public/assets/useRegisteredDebugTemplates-Bu2ykZ6s.js +1 -0
  47. package/dist/public/assets/workbench-navigation-DlgXuFW2.js +1 -0
  48. package/dist/public/index.html +2 -2
  49. package/dist/server/config/env.d.ts +1 -0
  50. package/dist/server/config/env.js +3 -0
  51. package/dist/server/config/env.js.map +1 -1
  52. package/dist/server/modules/affairs-indexer/core/src/parser/parser-skip-repository.js.map +1 -1
  53. package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-write-repository.js.map +1 -1
  54. package/dist/server/modules/affairs-indexer/core/src/sqlite/detect-catalog-schema.js +2 -2
  55. package/dist/server/modules/affairs-indexer/core/src/sqlite/detect-catalog-schema.js.map +1 -1
  56. package/dist/server/modules/affairs-indexer/core/src/sqlite/open-database.d.ts +20 -3
  57. package/dist/server/modules/affairs-indexer/core/src/sqlite/open-database.js +3 -3
  58. package/dist/server/modules/affairs-indexer/core/src/sqlite/open-database.js.map +1 -1
  59. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.d.ts +32 -0
  60. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.js +93 -0
  61. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.js.map +1 -0
  62. package/dist/server/modules/butler/assistant-sandbox-service.d.ts +69 -0
  63. package/dist/server/modules/butler/assistant-sandbox-service.js +399 -0
  64. package/dist/server/modules/butler/assistant-sandbox-service.js.map +1 -0
  65. package/dist/server/modules/butler/butler-follow-up-service.d.ts +3 -0
  66. package/dist/server/modules/butler/butler-follow-up-service.js +11 -1
  67. package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
  68. package/dist/server/modules/butler/butler-inbox-service.d.ts +3 -0
  69. package/dist/server/modules/butler/butler-inbox-service.js +14 -2
  70. package/dist/server/modules/butler/butler-inbox-service.js.map +1 -1
  71. package/dist/server/modules/butler/butler-session-service.d.ts +3 -0
  72. package/dist/server/modules/butler/butler-session-service.js +18 -0
  73. package/dist/server/modules/butler/butler-session-service.js.map +1 -1
  74. package/dist/server/modules/channels/wechat-claw-client.d.ts +51 -0
  75. package/dist/server/modules/channels/wechat-claw-client.js +245 -0
  76. package/dist/server/modules/channels/wechat-claw-client.js.map +1 -0
  77. package/dist/server/modules/file/file-controller.d.ts +11 -2
  78. package/dist/server/modules/file/file-controller.js +404 -17
  79. package/dist/server/modules/file/file-controller.js.map +1 -1
  80. package/dist/server/modules/file/file-search-service.js +200 -12
  81. package/dist/server/modules/file/file-search-service.js.map +1 -1
  82. package/dist/server/modules/file/runtime/codingns-workspace-bridge.js +18 -5
  83. package/dist/server/modules/file/workspace-file-bridge-service.d.ts +9 -0
  84. package/dist/server/modules/file/workspace-file-bridge-service.js +3 -0
  85. package/dist/server/modules/file/workspace-file-bridge-service.js.map +1 -1
  86. package/dist/server/modules/file/workspace-file-bridge-watch-service.d.ts +9 -0
  87. package/dist/server/modules/file/workspace-file-bridge-watch-service.js +28 -0
  88. package/dist/server/modules/file/workspace-file-bridge-watch-service.js.map +1 -1
  89. package/dist/server/modules/tasks/task-types.d.ts +1 -0
  90. package/dist/server/modules/tasks/task-types.js +1 -0
  91. package/dist/server/modules/tasks/task-types.js.map +1 -1
  92. package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.d.ts +1 -1
  93. package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.js +22 -5
  94. package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.js.map +1 -1
  95. package/dist/server/modules/workbench/workbench-controller.d.ts +5 -0
  96. package/dist/server/modules/workbench/workbench-controller.js +20 -0
  97. package/dist/server/modules/workbench/workbench-controller.js.map +1 -1
  98. package/dist/server/modules/workbench/workbench-service.d.ts +6 -6
  99. package/dist/server/modules/workbench/workbench-service.js +33 -36
  100. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  101. package/dist/server/modules/workspace/affairs-library-controller.d.ts +8 -0
  102. package/dist/server/modules/workspace/affairs-library-controller.js +11 -0
  103. package/dist/server/modules/workspace/affairs-library-controller.js.map +1 -1
  104. package/dist/server/modules/workspace/affairs-library-preview-link-service.d.ts +6 -0
  105. package/dist/server/modules/workspace/affairs-library-preview-link-service.js +12 -2
  106. package/dist/server/modules/workspace/affairs-library-preview-link-service.js.map +1 -1
  107. package/dist/server/modules/workspace/affairs-library-service.d.ts +9 -0
  108. package/dist/server/modules/workspace/affairs-library-service.js +182 -42
  109. package/dist/server/modules/workspace/affairs-library-service.js.map +1 -1
  110. package/dist/server/modules/workspace/affairs-lightweight-session-controller.d.ts +8 -0
  111. package/dist/server/modules/workspace/affairs-lightweight-session-controller.js +55 -8
  112. package/dist/server/modules/workspace/affairs-lightweight-session-controller.js.map +1 -1
  113. package/dist/server/modules/workspace/affairs-lightweight-session-service.d.ts +13 -0
  114. package/dist/server/modules/workspace/affairs-lightweight-session-service.js +167 -21
  115. package/dist/server/modules/workspace/affairs-lightweight-session-service.js.map +1 -1
  116. package/dist/server/modules/workspace/affairs-tag-controller.d.ts +3 -0
  117. package/dist/server/modules/workspace/affairs-tag-controller.js +5 -0
  118. package/dist/server/modules/workspace/affairs-tag-controller.js.map +1 -1
  119. package/dist/server/modules/workspace/affairs-tag-service.d.ts +22 -1
  120. package/dist/server/modules/workspace/affairs-tag-service.js +41 -2
  121. package/dist/server/modules/workspace/affairs-tag-service.js.map +1 -1
  122. package/dist/server/modules/workspace/teable-api-client.d.ts +118 -0
  123. package/dist/server/modules/workspace/teable-api-client.js +142 -0
  124. package/dist/server/modules/workspace/teable-api-client.js.map +1 -0
  125. package/dist/server/modules/workspace/teable-catalog-controller.d.ts +18 -0
  126. package/dist/server/modules/workspace/teable-catalog-controller.js +17 -0
  127. package/dist/server/modules/workspace/teable-catalog-controller.js.map +1 -0
  128. package/dist/server/modules/workspace/teable-catalog-service.d.ts +36 -0
  129. package/dist/server/modules/workspace/teable-catalog-service.js +124 -0
  130. package/dist/server/modules/workspace/teable-catalog-service.js.map +1 -0
  131. package/dist/server/modules/workspace/teable-credential-service.d.ts +8 -0
  132. package/dist/server/modules/workspace/teable-credential-service.js +37 -0
  133. package/dist/server/modules/workspace/teable-credential-service.js.map +1 -0
  134. package/dist/server/modules/workspace/teable-field-mapping-controller.d.ts +25 -0
  135. package/dist/server/modules/workspace/teable-field-mapping-controller.js +31 -0
  136. package/dist/server/modules/workspace/teable-field-mapping-controller.js.map +1 -0
  137. package/dist/server/modules/workspace/teable-field-mapping-service.d.ts +38 -0
  138. package/dist/server/modules/workspace/teable-field-mapping-service.js +215 -0
  139. package/dist/server/modules/workspace/teable-field-mapping-service.js.map +1 -0
  140. package/dist/server/modules/workspace/teable-global-binding-controller.d.ts +22 -0
  141. package/dist/server/modules/workspace/teable-global-binding-controller.js +25 -0
  142. package/dist/server/modules/workspace/teable-global-binding-controller.js.map +1 -0
  143. package/dist/server/modules/workspace/teable-global-binding-service.d.ts +35 -0
  144. package/dist/server/modules/workspace/teable-global-binding-service.js +151 -0
  145. package/dist/server/modules/workspace/teable-global-binding-service.js.map +1 -0
  146. package/dist/server/modules/workspace/teable-mirror-sync-controller.d.ts +29 -0
  147. package/dist/server/modules/workspace/teable-mirror-sync-controller.js +50 -0
  148. package/dist/server/modules/workspace/teable-mirror-sync-controller.js.map +1 -0
  149. package/dist/server/modules/workspace/teable-mirror-sync-service.d.ts +157 -0
  150. package/dist/server/modules/workspace/teable-mirror-sync-service.js +917 -0
  151. package/dist/server/modules/workspace/teable-mirror-sync-service.js.map +1 -0
  152. package/dist/server/modules/workspace/teable-runtime-controller.d.ts +58 -0
  153. package/dist/server/modules/workspace/teable-runtime-controller.js +60 -0
  154. package/dist/server/modules/workspace/teable-runtime-controller.js.map +1 -0
  155. package/dist/server/modules/workspace/teable-runtime-service.d.ts +96 -0
  156. package/dist/server/modules/workspace/teable-runtime-service.js +362 -0
  157. package/dist/server/modules/workspace/teable-runtime-service.js.map +1 -0
  158. package/dist/server/modules/workspace/teable-workbench-sync-config-controller.d.ts +22 -0
  159. package/dist/server/modules/workspace/teable-workbench-sync-config-controller.js +20 -0
  160. package/dist/server/modules/workspace/teable-workbench-sync-config-controller.js.map +1 -0
  161. package/dist/server/modules/workspace/teable-workbench-sync-config-service.d.ts +22 -0
  162. package/dist/server/modules/workspace/teable-workbench-sync-config-service.js +159 -0
  163. package/dist/server/modules/workspace/teable-workbench-sync-config-service.js.map +1 -0
  164. package/dist/server/routes/affairs.d.ts +9 -1
  165. package/dist/server/routes/affairs.js +120 -1
  166. package/dist/server/routes/affairs.js.map +1 -1
  167. package/dist/server/routes/workbench.js +15 -0
  168. package/dist/server/routes/workbench.js.map +1 -1
  169. package/dist/server/routes/workspaces.js +51 -41
  170. package/dist/server/routes/workspaces.js.map +1 -1
  171. package/dist/server/server/create-server.d.ts +14 -0
  172. package/dist/server/server/create-server.js +73 -7
  173. package/dist/server/server/create-server.js.map +1 -1
  174. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.d.ts +18 -0
  175. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js +191 -0
  176. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js.map +1 -0
  177. package/dist/server/storage/repositories/user-affairs-library-setting-repository.js +8 -5
  178. package/dist/server/storage/repositories/user-affairs-library-setting-repository.js.map +1 -1
  179. package/dist/server/storage/repositories/user-teable-credential-repository.d.ts +9 -0
  180. package/dist/server/storage/repositories/user-teable-credential-repository.js +45 -0
  181. package/dist/server/storage/repositories/user-teable-credential-repository.js.map +1 -0
  182. package/dist/server/storage/repositories/user-teable-field-mapping-repository.d.ts +10 -0
  183. package/dist/server/storage/repositories/user-teable-field-mapping-repository.js +69 -0
  184. package/dist/server/storage/repositories/user-teable-field-mapping-repository.js.map +1 -0
  185. package/dist/server/storage/repositories/user-teable-global-setting-repository.d.ts +8 -0
  186. package/dist/server/storage/repositories/user-teable-global-setting-repository.js +52 -0
  187. package/dist/server/storage/repositories/user-teable-global-setting-repository.js.map +1 -0
  188. package/dist/server/storage/repositories/user-teable-mirror-record-mapping-repository.d.ts +9 -0
  189. package/dist/server/storage/repositories/user-teable-mirror-record-mapping-repository.js +66 -0
  190. package/dist/server/storage/repositories/user-teable-mirror-record-mapping-repository.js.map +1 -0
  191. package/dist/server/storage/repositories/user-teable-mirror-table-binding-repository.d.ts +9 -0
  192. package/dist/server/storage/repositories/user-teable-mirror-table-binding-repository.js +67 -0
  193. package/dist/server/storage/repositories/user-teable-mirror-table-binding-repository.js.map +1 -0
  194. package/dist/server/storage/repositories/user-teable-sync-log-repository.d.ts +14 -0
  195. package/dist/server/storage/repositories/user-teable-sync-log-repository.js +97 -0
  196. package/dist/server/storage/repositories/user-teable-sync-log-repository.js.map +1 -0
  197. package/dist/server/storage/repositories/user-teable-workbench-sync-config-repository.d.ts +8 -0
  198. package/dist/server/storage/repositories/user-teable-workbench-sync-config-repository.js +55 -0
  199. package/dist/server/storage/repositories/user-teable-workbench-sync-config-repository.js.map +1 -0
  200. package/dist/server/storage/sqlite/client.js +404 -1
  201. package/dist/server/storage/sqlite/client.js.map +1 -1
  202. package/dist/server/storage/sqlite/schema.sql +167 -1
  203. package/dist/server/types/domain.d.ts +106 -0
  204. package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.d.ts +22 -3
  205. package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js +29 -2
  206. package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js.map +1 -1
  207. package/node_modules/@codingns/session-sync-core/package.json +3 -1
  208. package/package.json +1 -1
  209. package/dist/public/assets/DesktopWindowPage-D0blSuKd.js +0 -2
  210. package/dist/public/assets/FileContextPanel-BrKO8Xt6.js +0 -1
  211. package/dist/public/assets/GitSidebar-BdwiDtOr.js +0 -6
  212. package/dist/public/assets/MobileCreateSessionSheet-Cx_dBiBb.js +0 -1
  213. package/dist/public/assets/SettingsPage-BlAZCHsy.js +0 -2
  214. package/dist/public/assets/TerminalManagerPanel-CjzbiWjl.js +0 -1
  215. package/dist/public/assets/WorkbenchLayout-CikJBS62.js +0 -1019
  216. package/dist/public/assets/WorkbenchShellRoute-BbbSOiZw.js +0 -1
  217. package/dist/public/assets/WorkbenchShellRoute-DT3VMjWD.css +0 -1
  218. package/dist/public/assets/WorkspaceDebugDetailPage-CVivdPx5.js +0 -1
  219. package/dist/public/assets/WorkspaceDetailPage-DgOSjscR.js +0 -1
  220. package/dist/public/assets/WorkspaceHomePage-HPa7M_Vh.js +0 -1
  221. package/dist/public/assets/index-BxJPQpFM.css +0 -1
  222. package/dist/public/assets/index-CeXGOT_T.js +0 -50
  223. package/dist/public/assets/useRegisteredDebugTemplates-Bol3NVfN.js +0 -1
  224. package/dist/public/assets/workbench-navigation-B7IjRQd8.js +0 -1
@@ -12,6 +12,7 @@ import { isIncludedHiddenPath, normalizeIncludedHiddenPaths, SUPPORTED_INDEX_EXT
12
12
  import { writeAffairsLibraryDebugLog } from "./affairs-library-debug-log.js";
13
13
  import { AFFAIRS_LIBRARY_DEBUG_EVENTS, AFFAIRS_LIBRARY_INDEX_DIRTY_REASONS, AFFAIRS_LIBRARY_RECONCILE_REASONS, AFFAIRS_LIBRARY_RECONCILE_SCOPES, AFFAIRS_LIBRARY_RECONCILE_STATUSES } from "./affairs-library-refresh-contract.js";
14
14
  import { getSharedTaskHelperPool } from "../tasks/task-helper-pool.js";
15
+ export const AFFAIRS_GLOBAL_WORKSPACE_ID = "affairs-global";
15
16
  const DEFAULT_CONFIG_RELATIVE_PATH = ".ai-index/doc-semantic-index.config.json";
16
17
  const INDEX_DIR_RELATIVE_PATH = ".ai-index";
17
18
  const EXPORT_DIR_RELATIVE_PATH = ".ai-index/exports";
@@ -38,6 +39,32 @@ const SNAPSHOT_CACHE_SCHEMA_VERSION = 2;
38
39
  const HOT_DIRECTORY_CACHE_TTL_MS = 10 * 60 * 1000;
39
40
  const HOT_DIRECTORY_MAX_PER_WORKSPACE = 3;
40
41
  const LIVE_DIRECTORY_SYNC_SCAN_MAX_DOCUMENTS = 200;
42
+ function parseDashboardStateJson(value) {
43
+ const raw = value?.trim();
44
+ if (!raw) {
45
+ return {};
46
+ }
47
+ try {
48
+ return normalizeDashboardStatePayload(JSON.parse(raw));
49
+ }
50
+ catch {
51
+ return {};
52
+ }
53
+ }
54
+ function normalizeDashboardStatePayload(value) {
55
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
56
+ throw new AppError({
57
+ statusCode: 400,
58
+ errorCode: "INVALID_INPUT",
59
+ detail: "事务工作台配置必须是对象",
60
+ field: "dashboardState"
61
+ });
62
+ }
63
+ return {
64
+ ...value,
65
+ workspaceId: AFFAIRS_GLOBAL_WORKSPACE_ID
66
+ };
67
+ }
41
68
  export class AffairsLibraryService {
42
69
  workspaceService;
43
70
  workspaceNavigationStateRepository;
@@ -60,8 +87,8 @@ export class AffairsLibraryService {
60
87
  this.syncLightweightReconcileTimers();
61
88
  }
62
89
  getGlobalBinding(userId) {
63
- const setting = this.resolveLibrarySetting(userId, null);
64
- return this.buildBindingFromSetting(setting, null);
90
+ const setting = this.resolveLibrarySetting(userId, AFFAIRS_GLOBAL_WORKSPACE_ID);
91
+ return this.buildBindingFromSetting(setting, AFFAIRS_GLOBAL_WORKSPACE_ID);
65
92
  }
66
93
  getBinding(workspaceId, userId) {
67
94
  const setting = this.resolveLibrarySetting(userId, workspaceId);
@@ -71,21 +98,20 @@ export class AffairsLibraryService {
71
98
  const normalizedRootDir = this.normalizeAndValidateBindingRootDir(rootDir);
72
99
  const timestamp = nowIso();
73
100
  const currentSetting = this.resolveLibrarySetting(userId, null);
74
- const workspaceId = this.resolvePreferredWorkspaceId(currentSetting?.lastWorkspaceId ?? null);
101
+ const workspaceId = AFFAIRS_GLOBAL_WORKSPACE_ID;
75
102
  const nextSetting = this.upsertLibrarySetting({
76
103
  userId,
77
104
  rootDir: normalizedRootDir,
78
105
  enabled: true,
79
106
  favoritesJson: currentSetting?.favoritesJson ?? "[]",
80
107
  lastWorkspaceId: workspaceId ?? currentSetting?.lastWorkspaceId ?? null,
108
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
81
109
  createdAt: currentSetting?.createdAt ?? timestamp,
82
110
  updatedAt: timestamp
83
111
  });
84
112
  this.syncLightweightReconcileTimers();
85
- if (workspaceId) {
86
- this.scheduleAutoRefresh(workspaceId, "binding_saved");
87
- }
88
- return this.buildBindingFromSetting(nextSetting, null);
113
+ this.scheduleAutoRefresh(workspaceId, "binding_saved");
114
+ return this.buildBindingFromSetting(nextSetting, AFFAIRS_GLOBAL_WORKSPACE_ID);
89
115
  }
90
116
  setGlobalEnabled(userId, enabled) {
91
117
  const currentSetting = this.resolveLibrarySetting(userId, null);
@@ -100,39 +126,61 @@ export class AffairsLibraryService {
100
126
  if (enabled) {
101
127
  this.assertLibraryRootDir(rootDir);
102
128
  }
103
- const workspaceId = this.resolvePreferredWorkspaceId(currentSetting?.lastWorkspaceId ?? null);
129
+ const workspaceId = AFFAIRS_GLOBAL_WORKSPACE_ID;
104
130
  const nextSetting = this.upsertLibrarySetting({
105
131
  userId,
106
132
  rootDir,
107
133
  enabled,
108
134
  favoritesJson: currentSetting?.favoritesJson ?? "[]",
109
135
  lastWorkspaceId: workspaceId ?? currentSetting?.lastWorkspaceId ?? null,
136
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
110
137
  createdAt: currentSetting?.createdAt ?? nowIso(),
111
138
  updatedAt: nowIso()
112
139
  });
113
140
  this.syncLightweightReconcileTimers();
114
- if (enabled && workspaceId) {
141
+ if (enabled) {
115
142
  this.scheduleAutoRefresh(workspaceId, "library_enabled");
116
143
  }
117
- return this.buildBindingFromSetting(nextSetting, null);
144
+ return this.buildBindingFromSetting(nextSetting, AFFAIRS_GLOBAL_WORKSPACE_ID);
118
145
  }
119
146
  updateGlobalFavorites(userId, favorites) {
120
147
  const currentSetting = this.resolveLibrarySetting(userId, null);
121
148
  const normalizedFavorites = this.normalizeFavorites(favorites);
122
- const workspaceId = this.resolvePreferredWorkspaceId(currentSetting?.lastWorkspaceId ?? null);
149
+ const workspaceId = AFFAIRS_GLOBAL_WORKSPACE_ID;
123
150
  const nextSetting = this.upsertLibrarySetting({
124
151
  userId,
125
152
  rootDir: currentSetting?.rootDir ?? null,
126
153
  enabled: currentSetting?.enabled ?? false,
127
154
  favoritesJson: JSON.stringify(normalizedFavorites),
128
155
  lastWorkspaceId: workspaceId ?? currentSetting?.lastWorkspaceId ?? null,
156
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
129
157
  createdAt: currentSetting?.createdAt ?? nowIso(),
130
158
  updatedAt: nowIso()
131
159
  });
132
160
  return normalizedFavorites;
133
161
  }
162
+ getGlobalDashboardState(userId) {
163
+ const currentSetting = this.resolveLibrarySetting(userId, null);
164
+ return parseDashboardStateJson(currentSetting?.dashboardStateJson);
165
+ }
166
+ updateGlobalDashboardState(userId, dashboardState) {
167
+ const normalizedState = normalizeDashboardStatePayload(dashboardState);
168
+ const currentSetting = this.resolveLibrarySetting(userId, null);
169
+ const timestamp = nowIso();
170
+ this.upsertLibrarySetting({
171
+ userId,
172
+ rootDir: currentSetting?.rootDir ?? null,
173
+ enabled: currentSetting?.enabled ?? false,
174
+ favoritesJson: currentSetting?.favoritesJson ?? "[]",
175
+ lastWorkspaceId: AFFAIRS_GLOBAL_WORKSPACE_ID,
176
+ dashboardStateJson: JSON.stringify(normalizedState),
177
+ createdAt: currentSetting?.createdAt ?? timestamp,
178
+ updatedAt: timestamp
179
+ });
180
+ return normalizedState;
181
+ }
134
182
  saveBinding(workspaceId, userId, rootDir) {
135
- this.workspaceService.getWorkspaceOrThrow(workspaceId);
183
+ this.assertWorkspaceIdCanUseLegacyAffairsRoute(workspaceId);
136
184
  const normalizedRootDir = this.normalizeAndValidateBindingRootDir(rootDir);
137
185
  const timestamp = nowIso();
138
186
  const currentSetting = this.resolveLibrarySetting(userId, workspaceId);
@@ -142,6 +190,7 @@ export class AffairsLibraryService {
142
190
  enabled: true,
143
191
  favoritesJson: currentSetting?.favoritesJson ?? "[]",
144
192
  lastWorkspaceId: workspaceId,
193
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
145
194
  createdAt: currentSetting?.createdAt ?? timestamp,
146
195
  updatedAt: timestamp
147
196
  });
@@ -150,7 +199,7 @@ export class AffairsLibraryService {
150
199
  return this.buildBindingFromSetting(nextSetting, workspaceId);
151
200
  }
152
201
  setEnabled(workspaceId, userId, enabled) {
153
- this.workspaceService.getWorkspaceOrThrow(workspaceId);
202
+ this.assertWorkspaceIdCanUseLegacyAffairsRoute(workspaceId);
154
203
  const currentSetting = this.resolveLibrarySetting(userId, workspaceId);
155
204
  const rootDir = currentSetting?.rootDir?.trim() ?? "";
156
205
  if (!rootDir) {
@@ -169,6 +218,7 @@ export class AffairsLibraryService {
169
218
  enabled,
170
219
  favoritesJson: currentSetting?.favoritesJson ?? "[]",
171
220
  lastWorkspaceId: workspaceId,
221
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
172
222
  createdAt: currentSetting?.createdAt ?? nowIso(),
173
223
  updatedAt: nowIso()
174
224
  });
@@ -308,6 +358,7 @@ export class AffairsLibraryService {
308
358
  if (!binding || !binding.enabled) {
309
359
  return {
310
360
  total: 0,
361
+ visibleEntryTotal: 0,
311
362
  offset: 0,
312
363
  limit: normalizePositiveInt(input.limit, 120, 400),
313
364
  items: [],
@@ -320,12 +371,14 @@ export class AffairsLibraryService {
320
371
  const browseMode = input.browseMode === "tag" ? "tag" : "folder";
321
372
  const offset = Math.max(0, normalizePositiveInt(input.offset, 0, Number.MAX_SAFE_INTEGER));
322
373
  const limit = normalizePositiveInt(input.limit, 120, 400);
374
+ const normalizedKeyword = normalizeDocumentSearchKeyword(input.keyword);
323
375
  const indexStatus = this.readIndexStatus(workspaceId, binding);
324
376
  const selectedFavorite = favorites.find((item) => buildFavoriteNodeId(item.kind, item.path) === (input.selectedFavoriteId?.trim() ?? "")) ?? null;
325
377
  const normalizedSelectedTagPaths = normalizeSelectedTagPaths(input.selectedTagPaths);
326
378
  if (browseMode === "folder") {
327
379
  return this.listLiveFolderDocuments(workspaceId, binding.rootDir, favorites, exportData, selectedFavorite, {
328
380
  selectedFolderPath: input.selectedFolderPath,
381
+ keyword: normalizedKeyword,
329
382
  offset,
330
383
  limit,
331
384
  indexStatus
@@ -334,6 +387,7 @@ export class AffairsLibraryService {
334
387
  if (!exportData) {
335
388
  return {
336
389
  total: 0,
390
+ visibleEntryTotal: 0,
337
391
  offset,
338
392
  limit,
339
393
  items: [],
@@ -342,6 +396,9 @@ export class AffairsLibraryService {
342
396
  };
343
397
  }
344
398
  const filtered = exportData.documents.filter((document) => {
399
+ if (!matchesDocumentKeyword(document, normalizedKeyword)) {
400
+ return false;
401
+ }
345
402
  if (browseMode === "tag") {
346
403
  const tagPaths = selectedFavorite?.kind === "tag"
347
404
  ? [selectedFavorite.path]
@@ -366,6 +423,7 @@ export class AffairsLibraryService {
366
423
  });
367
424
  return {
368
425
  total: filtered.length,
426
+ visibleEntryTotal: filtered.length,
369
427
  offset,
370
428
  limit,
371
429
  items,
@@ -409,7 +467,7 @@ export class AffairsLibraryService {
409
467
  ? fallbackResult.source
410
468
  : directoryResult.source;
411
469
  if (!liveScanDecision.avoidSyncScan) {
412
- this.updateHotDirectoryCache(workspaceId, rootDir, normalizedDirectoryPath, items, directoryResult.source, {
470
+ this.updateHotDirectoryCache(workspaceId, rootDir, normalizedDirectoryPath, items, directoryResult.childDirectoryCount, directoryResult.source, {
413
471
  preserveStatus: directoryStatus.state === "running" || directoryStatus.state === "queued"
414
472
  || directoryStatus.state === "queue_timeout",
415
473
  generatedAt: directoryResult.generatedAt,
@@ -436,6 +494,7 @@ export class AffairsLibraryService {
436
494
  else {
437
495
  const fallbackEntry = this.getOrCreateHotDirectoryEntry(workspaceId, rootDir, normalizedDirectoryPath);
438
496
  fallbackEntry.items = directoryResult.items;
497
+ fallbackEntry.childDirectoryCount = directoryResult.childDirectoryCount;
439
498
  fallbackEntry.source = directoryResult.source;
440
499
  fallbackEntry.generatedAt = directoryResult.generatedAt;
441
500
  fallbackEntry.filesystemObservedAt = directoryResult.filesystemObservedAt;
@@ -455,7 +514,12 @@ export class AffairsLibraryService {
455
514
  && directoryStatus.state !== "queued") {
456
515
  this.scheduleDirectoryHintRefresh(workspaceId, normalizedDirectoryPath, "large_directory_live_scan");
457
516
  }
458
- const resultItems = items.slice(input.offset, input.offset + input.limit);
517
+ const keyword = input.keyword?.trim() ?? "";
518
+ const filteredItems = keyword
519
+ ? items.filter((item) => matchesDocumentKeyword(item, keyword))
520
+ : items;
521
+ const resultItems = filteredItems.slice(input.offset, input.offset + input.limit);
522
+ const visibleEntryTotal = directoryResult.childDirectoryCount + filteredItems.length;
459
523
  writeAffairsLibraryDebugLog({
460
524
  event: "folder_list_served",
461
525
  processRole: "host",
@@ -473,7 +537,9 @@ export class AffairsLibraryService {
473
537
  generatedAt: directoryResult.generatedAt,
474
538
  filesystemObservedAt: directoryResult.filesystemObservedAt,
475
539
  estimatedDocumentCount: liveScanDecision.estimatedDocumentCount,
476
- total: items.length,
540
+ total: filteredItems.length,
541
+ visibleEntryTotal,
542
+ childDirectoryCount: directoryResult.childDirectoryCount,
477
543
  returned: resultItems.length,
478
544
  offset: input.offset,
479
545
  limit: input.limit,
@@ -481,7 +547,8 @@ export class AffairsLibraryService {
481
547
  }
482
548
  });
483
549
  return {
484
- total: items.length,
550
+ total: filteredItems.length,
551
+ visibleEntryTotal,
485
552
  offset: input.offset,
486
553
  limit: input.limit,
487
554
  items: resultItems,
@@ -574,6 +641,7 @@ export class AffairsLibraryService {
574
641
  if (cached && cached.items.length > 0) {
575
642
  return {
576
643
  items: cached.items,
644
+ childDirectoryCount: cached.childDirectoryCount,
577
645
  source: staleReason ? "stale_fallback" : cached.source,
578
646
  generatedAt: cached.generatedAt,
579
647
  filesystemObservedAt: cached.filesystemObservedAt,
@@ -598,6 +666,7 @@ export class AffairsLibraryService {
598
666
  }));
599
667
  return {
600
668
  items,
669
+ childDirectoryCount: countDirectChildFoldersFromSnapshot(normalizedFolderPath, exportData),
601
670
  source: directoryStatus?.source ?? "snapshot",
602
671
  generatedAt: exportData?.generatedAt ?? directoryStatus?.generatedAt ?? null,
603
672
  filesystemObservedAt: directoryStatus?.filesystemObservedAt ?? null,
@@ -633,7 +702,7 @@ export class AffairsLibraryService {
633
702
  });
634
703
  }
635
704
  updateFavorites(workspaceId, userId, favorites) {
636
- this.workspaceService.getWorkspaceOrThrow(workspaceId);
705
+ this.assertWorkspaceIdCanUseLegacyAffairsRoute(workspaceId);
637
706
  const currentSetting = this.resolveLibrarySetting(userId, workspaceId);
638
707
  const normalizedFavorites = this.normalizeFavorites(favorites);
639
708
  const nextSetting = this.upsertLibrarySetting({
@@ -642,6 +711,7 @@ export class AffairsLibraryService {
642
711
  enabled: currentSetting?.enabled ?? false,
643
712
  favoritesJson: JSON.stringify(normalizedFavorites),
644
713
  lastWorkspaceId: workspaceId,
714
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
645
715
  createdAt: currentSetting?.createdAt ?? nowIso(),
646
716
  updatedAt: nowIso()
647
717
  });
@@ -1581,6 +1651,7 @@ export class AffairsLibraryService {
1581
1651
  rootDir,
1582
1652
  directoryPath: normalizedDirectoryPath,
1583
1653
  items: [],
1654
+ childDirectoryCount: 0,
1584
1655
  updatedAtMs: 0,
1585
1656
  source: "snapshot",
1586
1657
  dirty: true,
@@ -1598,10 +1669,11 @@ export class AffairsLibraryService {
1598
1669
  this.hotDirectoryCache.set(cacheKey, entry);
1599
1670
  return entry;
1600
1671
  }
1601
- updateHotDirectoryCache(workspaceId, rootDir, directoryPath, items, source, options = {}) {
1672
+ updateHotDirectoryCache(workspaceId, rootDir, directoryPath, items, childDirectoryCount, source, options = {}) {
1602
1673
  const entry = this.getOrCreateHotDirectoryEntry(workspaceId, rootDir, directoryPath);
1603
1674
  entry.rootDir = rootDir;
1604
1675
  entry.items = items;
1676
+ entry.childDirectoryCount = childDirectoryCount;
1605
1677
  entry.updatedAtMs = Date.now();
1606
1678
  entry.source = source;
1607
1679
  entry.lastRefreshRequestedAt = options.requestedAt ?? entry.lastRefreshRequestedAt;
@@ -1721,6 +1793,7 @@ export class AffairsLibraryService {
1721
1793
  refreshedAt: completedAt,
1722
1794
  source: liveResult.source,
1723
1795
  itemCount: liveResult.items.length,
1796
+ childDirectoryCount: liveResult.childDirectoryCount,
1724
1797
  changedPaths,
1725
1798
  items: liveResult.items,
1726
1799
  generatedAt: liveResult.generatedAt,
@@ -1742,7 +1815,7 @@ export class AffairsLibraryService {
1742
1815
  status: "queued"
1743
1816
  });
1744
1817
  void handle.promise.then((result) => {
1745
- this.updateHotDirectoryCache(workspaceId, meta.rootDir, meta.directoryPath, result.items, result.source, {
1818
+ this.updateHotDirectoryCache(workspaceId, meta.rootDir, meta.directoryPath, result.items, result.childDirectoryCount, result.source, {
1746
1819
  requestedAt: this.getOrCreateHotDirectoryEntry(workspaceId, meta.rootDir, meta.directoryPath).lastRefreshRequestedAt,
1747
1820
  completedAt: result.refreshedAt,
1748
1821
  errorSummary: null,
@@ -2735,7 +2808,9 @@ export class AffairsLibraryService {
2735
2808
  }
2736
2809
  const config = this.readConfig(rootDir);
2737
2810
  return {
2738
- workspaceId: setting?.lastWorkspaceId ?? fallbackWorkspaceId,
2811
+ workspaceId: fallbackWorkspaceId === AFFAIRS_GLOBAL_WORKSPACE_ID
2812
+ ? AFFAIRS_GLOBAL_WORKSPACE_ID
2813
+ : setting?.lastWorkspaceId ?? fallbackWorkspaceId,
2739
2814
  rootDir,
2740
2815
  enabled: setting?.enabled === true,
2741
2816
  mirrorRoot: config.mirrorRoot,
@@ -2786,7 +2861,8 @@ export class AffairsLibraryService {
2786
2861
  rootDir: legacyRootDir,
2787
2862
  enabled: legacy?.affairsLibraryEnabled === true,
2788
2863
  favoritesJson: legacy?.affairsLibraryFavoritesJson ?? "[]",
2789
- lastWorkspaceId: legacy?.workspaceId ?? (workspaceScope || null),
2864
+ lastWorkspaceId: AFFAIRS_GLOBAL_WORKSPACE_ID,
2865
+ dashboardStateJson: currentSetting?.dashboardStateJson ?? "{}",
2790
2866
  createdAt: currentSetting?.createdAt ?? legacy?.updatedAt ?? nowIso(),
2791
2867
  updatedAt: legacy?.updatedAt ?? nowIso()
2792
2868
  });
@@ -2798,7 +2874,8 @@ export class AffairsLibraryService {
2798
2874
  rootDir: record.rootDir?.trim() || null,
2799
2875
  enabled: record.enabled === true,
2800
2876
  favoritesJson: record.favoritesJson ?? null,
2801
- lastWorkspaceId: record.lastWorkspaceId?.trim() || null,
2877
+ lastWorkspaceId: this.normalizeAffairsWorkspaceId(record.lastWorkspaceId),
2878
+ dashboardStateJson: record.dashboardStateJson?.trim() || "{}",
2802
2879
  createdAt: record.createdAt,
2803
2880
  updatedAt: record.updatedAt
2804
2881
  });
@@ -2807,7 +2884,7 @@ export class AffairsLibraryService {
2807
2884
  if (typeof this.userAffairsLibrarySettingRepository.listEnabled === "function") {
2808
2885
  return this.userAffairsLibrarySettingRepository
2809
2886
  .listEnabled()
2810
- .filter((item) => Boolean(item.lastWorkspaceId?.trim() && item.rootDir?.trim()));
2887
+ .filter((item) => Boolean(item.rootDir?.trim()));
2811
2888
  }
2812
2889
  return this.workspaceNavigationStateRepository
2813
2890
  .listEnabledAffairsLibraries()
@@ -2816,19 +2893,26 @@ export class AffairsLibraryService {
2816
2893
  rootDir: item.affairsLibraryRootPath ?? null,
2817
2894
  enabled: item.affairsLibraryEnabled === true,
2818
2895
  favoritesJson: item.affairsLibraryFavoritesJson ?? null,
2819
- lastWorkspaceId: item.workspaceId,
2896
+ lastWorkspaceId: AFFAIRS_GLOBAL_WORKSPACE_ID,
2897
+ dashboardStateJson: "{}",
2820
2898
  createdAt: item.updatedAt,
2821
2899
  updatedAt: item.updatedAt
2822
2900
  }))
2823
- .filter((item) => Boolean(item.lastWorkspaceId?.trim() && item.rootDir?.trim()));
2901
+ .filter((item) => Boolean(item.rootDir?.trim()));
2824
2902
  }
2825
2903
  findEnabledBindingByWorkspaceId(workspaceId) {
2826
- const normalizedWorkspaceId = workspaceId.trim();
2827
- if (!normalizedWorkspaceId) {
2828
- return null;
2829
- }
2904
+ const normalizedWorkspaceId = this.normalizeAffairsWorkspaceId(workspaceId);
2830
2905
  if (typeof this.userAffairsLibrarySettingRepository.findEnabledByWorkspaceId === "function") {
2831
- return this.userAffairsLibrarySettingRepository.findEnabledByWorkspaceId(normalizedWorkspaceId);
2906
+ const direct = this.userAffairsLibrarySettingRepository.findEnabledByWorkspaceId(normalizedWorkspaceId);
2907
+ if (direct) {
2908
+ return direct;
2909
+ }
2910
+ if (normalizedWorkspaceId === AFFAIRS_GLOBAL_WORKSPACE_ID && typeof this.userAffairsLibrarySettingRepository.listEnabled === "function") {
2911
+ return this.userAffairsLibrarySettingRepository
2912
+ .listEnabled()
2913
+ .find((item) => item.rootDir?.trim() && item.enabled === true) ?? null;
2914
+ }
2915
+ return null;
2832
2916
  }
2833
2917
  const legacy = this.workspaceNavigationStateRepository.findAnyEnabledAffairsLibraryByWorkspaceId(normalizedWorkspaceId);
2834
2918
  if (!legacy?.affairsLibraryRootPath?.trim()) {
@@ -2840,10 +2924,21 @@ export class AffairsLibraryService {
2840
2924
  enabled: legacy.affairsLibraryEnabled === true,
2841
2925
  favoritesJson: legacy.affairsLibraryFavoritesJson ?? null,
2842
2926
  lastWorkspaceId: legacy.workspaceId,
2927
+ dashboardStateJson: "{}",
2843
2928
  createdAt: legacy.updatedAt,
2844
2929
  updatedAt: legacy.updatedAt
2845
2930
  };
2846
2931
  }
2932
+ normalizeAffairsWorkspaceId(workspaceId) {
2933
+ return workspaceId?.trim() || AFFAIRS_GLOBAL_WORKSPACE_ID;
2934
+ }
2935
+ assertWorkspaceIdCanUseLegacyAffairsRoute(workspaceId) {
2936
+ const normalizedWorkspaceId = workspaceId.trim();
2937
+ if (!normalizedWorkspaceId || normalizedWorkspaceId === AFFAIRS_GLOBAL_WORKSPACE_ID) {
2938
+ return;
2939
+ }
2940
+ this.workspaceService.getWorkspaceOrThrow(normalizedWorkspaceId);
2941
+ }
2847
2942
  normalizeAndValidateBindingRootDir(rootDir) {
2848
2943
  const normalizedRootDir = rootDir.trim();
2849
2944
  if (!normalizedRootDir) {
@@ -2882,17 +2977,7 @@ export class AffairsLibraryService {
2882
2977
  }));
2883
2978
  }
2884
2979
  resolvePreferredWorkspaceId(preferredWorkspaceId) {
2885
- const normalizedPreferredWorkspaceId = preferredWorkspaceId?.trim() ?? "";
2886
- if (normalizedPreferredWorkspaceId) {
2887
- try {
2888
- this.workspaceService.getWorkspaceOrThrow(normalizedPreferredWorkspaceId);
2889
- return normalizedPreferredWorkspaceId;
2890
- }
2891
- catch {
2892
- // 旧的随机 workspaceId 已经失效时,直接降级到当前仍可见的工作区。
2893
- }
2894
- }
2895
- return this.workspaceService.list()[0]?.id ?? null;
2980
+ return this.normalizeAffairsWorkspaceId(preferredWorkspaceId);
2896
2981
  }
2897
2982
  ensureLibraryEnabled(binding) {
2898
2983
  if (binding.enabled) {
@@ -3209,6 +3294,21 @@ function shouldForceFullRebuild(reason) {
3209
3294
  || normalizedReason.includes(AFFAIRS_LIBRARY_INDEX_DIRTY_REASONS.missingExportStatus)
3210
3295
  || normalizedReason.includes(AFFAIRS_LIBRARY_INDEX_DIRTY_REASONS.missingExportManifest);
3211
3296
  }
3297
+ function normalizeDocumentSearchKeyword(value) {
3298
+ return value?.trim().toLowerCase() ?? "";
3299
+ }
3300
+ function matchesDocumentKeyword(document, normalizedKeyword) {
3301
+ if (!normalizedKeyword) {
3302
+ return true;
3303
+ }
3304
+ return [
3305
+ document.title,
3306
+ document.path,
3307
+ document.summary,
3308
+ ...document.tags,
3309
+ ...document.derivedTags
3310
+ ].some((value) => value?.toLowerCase().includes(normalizedKeyword));
3311
+ }
3212
3312
  function matchesFavorite(favorite, documentPath, directTags, derivedTags) {
3213
3313
  if (favorite.kind === "folder") {
3214
3314
  const normalizedPath = favorite.path === "." ? "" : favorite.path.replace(/\/+$/g, "");
@@ -3331,6 +3431,44 @@ function readAffairsLibraryConfigSafe(rootDir) {
3331
3431
  folderOpenBehavior: normalizeFolderOpenBehavior(payload.folderOpenBehavior)
3332
3432
  };
3333
3433
  }
3434
+ function countDirectChildFoldersFromSnapshot(normalizedFolderPath, exportData) {
3435
+ if (!exportData) {
3436
+ return 0;
3437
+ }
3438
+ const normalizedCurrentPath = normalizeFolderPath(normalizedFolderPath);
3439
+ return exportData.folders.filter((folder) => normalizeFolderPath(folder.parentPath) === normalizedCurrentPath).length;
3440
+ }
3441
+ function countVisibleDirectChildDirectories(targetDir, normalizedFolderPath, includedHiddenPaths) {
3442
+ if (!fs.existsSync(targetDir)) {
3443
+ return 0;
3444
+ }
3445
+ let stats = null;
3446
+ try {
3447
+ stats = fs.statSync(targetDir);
3448
+ }
3449
+ catch {
3450
+ stats = null;
3451
+ }
3452
+ if (!stats?.isDirectory()) {
3453
+ return 0;
3454
+ }
3455
+ let count = 0;
3456
+ for (const entry of fs.readdirSync(targetDir, { withFileTypes: true })) {
3457
+ if (!entry.isDirectory() || entry.isSymbolicLink()) {
3458
+ continue;
3459
+ }
3460
+ const relativePath = normalizedFolderPath ? `${normalizedFolderPath}/${entry.name}` : entry.name;
3461
+ if (relativePath === '.ai-index' || relativePath.startsWith('.ai-index/')) {
3462
+ continue;
3463
+ }
3464
+ if ((entry.name.startsWith('.') || hasHiddenPathSegment(relativePath))
3465
+ && !isIncludedHiddenPath(relativePath, includedHiddenPaths)) {
3466
+ continue;
3467
+ }
3468
+ count += 1;
3469
+ }
3470
+ return count;
3471
+ }
3334
3472
  function buildAffairsFolderDocumentsFromFilesystem(rootDir, normalizedFolderPath, exportData, config, supportedExtensions = new Set(SUPPORTED_INDEX_EXTENSION_LIST)) {
3335
3473
  const targetDir = normalizedFolderPath
3336
3474
  ? path.resolve(rootDir, normalizedFolderPath)
@@ -3405,6 +3543,7 @@ function buildAffairsFolderDocumentsFromFilesystem(rootDir, normalizedFolderPath
3405
3543
  }
3406
3544
  return {
3407
3545
  items: [...documentMap.values()],
3546
+ childDirectoryCount: countVisibleDirectChildDirectories(targetDir, normalizedFolderPath, config.includedHiddenPaths),
3408
3547
  source: hasLiveData && hasSnapshotData
3409
3548
  ? "mixed"
3410
3549
  : hasLiveData
@@ -3426,6 +3565,7 @@ export async function runAffairsLibraryDirectoryHintInHelper(input) {
3426
3565
  refreshedAt: nowIso(),
3427
3566
  source: result.source,
3428
3567
  itemCount: result.items.length,
3568
+ childDirectoryCount: result.childDirectoryCount,
3429
3569
  changedPaths: result.items.map((item) => item.path).sort((left, right) => left.localeCompare(right, "zh-CN")),
3430
3570
  items: result.items,
3431
3571
  generatedAt: result.generatedAt,