nolo-cli 0.1.40 → 0.1.42

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 (482) hide show
  1. package/README.md +27 -12
  2. package/agent-runtime/agentThread.ts +222 -0
  3. package/agent-runtime/agentThreadAdmission.ts +74 -0
  4. package/agent-runtime/dialogWritePlan.ts +42 -0
  5. package/agent-runtime/hostAdapter.ts +1 -0
  6. package/agent-runtime/hybridRecordStore.ts +5 -3
  7. package/agent-runtime/index.ts +43 -0
  8. package/agent-runtime/localLoop.ts +31 -2
  9. package/agent-runtime/localToolPolicy.ts +1 -0
  10. package/agent-runtime/localWorkspaceTools.ts +1258 -78
  11. package/agent-runtime/noloWorkspaceTools.ts +20 -1
  12. package/agent-runtime/runtimeToolPolicy.ts +1 -5
  13. package/agent-runtime/runtimeToolSurface.ts +1 -0
  14. package/agentAliases.ts +29 -9
  15. package/agentInternalCommandEntries.ts +11 -3
  16. package/agentMachineCommands.ts +1 -0
  17. package/agentRecordCommands.ts +2 -2
  18. package/agentRecordHelpers.ts +59 -6
  19. package/agentRunCommand.ts +84 -19
  20. package/ai/agent/_executeModel.ts +146 -0
  21. package/ai/agent/agentSlice.ts +556 -1
  22. package/ai/agent/appWorkingMemory.ts +126 -0
  23. package/ai/agent/buildEditingContext.ts +378 -0
  24. package/ai/agent/buildSystemPrompt.ts +599 -0
  25. package/ai/agent/canvasEditingContext.ts +49 -0
  26. package/ai/agent/cleanAgentMessages.ts +140 -0
  27. package/ai/agent/cliChatClient.ts +153 -0
  28. package/ai/agent/cliExecutor.ts +264 -46
  29. package/ai/agent/contextCompiler.ts +107 -0
  30. package/ai/agent/contextLayerContract.ts +44 -0
  31. package/ai/agent/createAgentSchema.ts +272 -0
  32. package/ai/agent/currentTimeContext.ts +65 -0
  33. package/ai/agent/executeToolCall.ts +58 -0
  34. package/ai/agent/fetchAgentContexts.ts +42 -0
  35. package/ai/agent/generatePrompt.ts +3 -0
  36. package/ai/agent/getFullChatContextKeys.ts +168 -0
  37. package/ai/agent/guidedCreation/capabilities.ts +84 -0
  38. package/ai/agent/guidedCreation/types.ts +38 -0
  39. package/ai/agent/isLiveAudioOnlyAgent.ts +26 -0
  40. package/ai/agent/liveAudioModel.ts +2 -0
  41. package/ai/agent/pageBuilderHandoffRules.ts +75 -0
  42. package/ai/agent/persistMessageWithFixedId.ts +37 -0
  43. package/ai/agent/planSlice.ts +259 -0
  44. package/ai/agent/referenceUtils.ts +229 -0
  45. package/ai/agent/runAgentBackground.ts +310 -0
  46. package/ai/agent/runAgentClientLoop.ts +164 -0
  47. package/ai/agent/runtimeGuidance.ts +116 -0
  48. package/ai/agent/serverOrigin.ts +7 -0
  49. package/ai/agent/startParallelAgentStreams.ts +424 -0
  50. package/ai/agent/startupProtocol.ts +53 -0
  51. package/ai/agent/streamAgentChatTurn.ts +2135 -0
  52. package/ai/agent/streamAgentChatTurnUtils.ts +923 -0
  53. package/ai/agent/toolFailureGuard.ts +99 -0
  54. package/ai/agent/types.ts +73 -0
  55. package/ai/agent/utils/imageOutput.ts +37 -0
  56. package/ai/agent/utils/publicImageAgentMode.ts +26 -0
  57. package/ai/ai.locale.ts +1165 -0
  58. package/ai/chat/accumulateToolCallChunks.ts +126 -0
  59. package/ai/chat/fetchUtils.ts +143 -0
  60. package/ai/chat/inlineImageUrlsForCustomProvider.ts +122 -0
  61. package/ai/chat/parseApiError.ts +67 -0
  62. package/ai/chat/parseMultilineSSE.ts +95 -0
  63. package/ai/chat/sendOpenAICompletionsRequest.ts +921 -0
  64. package/ai/chat/sendOpenAIResponseRequest.ts +720 -0
  65. package/ai/chat/serverProxyRetry.ts +102 -0
  66. package/ai/chat/shouldUseServerProxy.ts +18 -0
  67. package/ai/chat/streamRetry.ts +46 -0
  68. package/ai/chat/updateTotalUsage.ts +89 -0
  69. package/ai/context/buildReferenceContext.ts +437 -0
  70. package/ai/context/retention.ts +165 -0
  71. package/ai/context/tokenUtils.ts +78 -0
  72. package/ai/llm/agentCapabilities.ts +74 -0
  73. package/ai/llm/deepinfra.ts +79 -0
  74. package/ai/llm/fireworks.ts +68 -0
  75. package/ai/llm/generateRequestBody.ts +165 -0
  76. package/ai/llm/getModelContextWindow.ts +93 -0
  77. package/ai/llm/getPricing.ts +252 -0
  78. package/ai/llm/imagePricing.ts +66 -0
  79. package/ai/llm/isResponseAPIModel.ts +13 -0
  80. package/ai/llm/kimi.ts +22 -0
  81. package/ai/llm/mimo.ts +99 -0
  82. package/ai/llm/mistral.ts +21 -0
  83. package/ai/llm/models.ts +45 -0
  84. package/ai/llm/openrouterModels.ts +31 -0
  85. package/ai/llm/providers.ts +313 -0
  86. package/ai/llm/reasoningModels.ts +27 -0
  87. package/ai/llm/types.ts +82 -0
  88. package/ai/llm/usageRequestOptions.ts +59 -0
  89. package/ai/memory/policy.ts +49 -0
  90. package/ai/memory/queryShared.ts +167 -0
  91. package/ai/memory/recentRelationshipRecap.ts +251 -0
  92. package/ai/memory/remember.ts +111 -0
  93. package/ai/memory/scope.ts +74 -0
  94. package/ai/memory/store.ts +20 -0
  95. package/ai/memory/storeShared.ts +76 -0
  96. package/ai/memory/types.ts +52 -0
  97. package/ai/memory/understanding.ts +341 -0
  98. package/ai/memory/understandingGreeting.ts +264 -0
  99. package/ai/policy/personalizationDialog.ts +333 -0
  100. package/ai/policy/runtimePolicy.ts +526 -0
  101. package/ai/policy/selfUpdateFields.ts +48 -0
  102. package/ai/policy/types.ts +64 -0
  103. package/ai/skills/referenceRuntime.ts +274 -0
  104. package/ai/skills/skillDiagnostics.ts +251 -0
  105. package/ai/skills/skillDocBuilder.ts +139 -0
  106. package/ai/skills/skillSummaryMarker.ts +26 -0
  107. package/ai/token/calculatePrice.ts +576 -0
  108. package/ai/token/missingUsageEstimate.ts +42 -0
  109. package/ai/token/normalizeUsage.ts +124 -0
  110. package/ai/token/openaiImageGenerationUsage.ts +56 -0
  111. package/ai/token/prepareTokenUsageData.ts +93 -0
  112. package/ai/token/resolveBillingTarget.ts +52 -0
  113. package/ai/token/saveTokenRecord.ts +53 -0
  114. package/ai/token/types.ts +103 -0
  115. package/ai/tools/agent/agentTools.ts +214 -0
  116. package/ai/tools/agent/agentUpdateShared.ts +311 -0
  117. package/ai/tools/agent/callAgentTool.ts +139 -0
  118. package/ai/tools/agent/createAgentTool.ts +512 -0
  119. package/ai/tools/agent/createDialogTool.ts +69 -0
  120. package/ai/tools/agent/createSkillAgentTool.ts +62 -0
  121. package/ai/tools/agent/parallelBudget.ts +221 -0
  122. package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
  123. package/ai/tools/agent/presets/appBuilderPreset.ts +154 -0
  124. package/ai/tools/agent/runLlmTool.ts +96 -0
  125. package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
  126. package/ai/tools/agent/skillAgentArgs.ts +106 -0
  127. package/ai/tools/agent/startAgentDialogTool.ts +54 -0
  128. package/ai/tools/agent/streamParallelAgentsTool.ts +123 -0
  129. package/ai/tools/agent/updateAgentTool.ts +96 -0
  130. package/ai/tools/agent/updateSelfTool.ts +113 -0
  131. package/ai/tools/amazonProductScraperTool.ts +86 -0
  132. package/ai/tools/apifyActorClient.ts +45 -0
  133. package/ai/tools/appEditGuard.ts +372 -0
  134. package/ai/tools/appReadSnapshot.ts +153 -0
  135. package/ai/tools/appTools.ts +1549 -0
  136. package/ai/tools/applyEditTool.ts +259 -0
  137. package/ai/tools/applyLineEditsTool.ts +315 -0
  138. package/ai/tools/browserTools/click.ts +33 -0
  139. package/ai/tools/browserTools/closeSession.ts +29 -0
  140. package/ai/tools/browserTools/common.ts +27 -0
  141. package/ai/tools/browserTools/openSession.ts +48 -0
  142. package/ai/tools/browserTools/readContent.ts +38 -0
  143. package/ai/tools/browserTools/selectOption.ts +46 -0
  144. package/ai/tools/browserTools/typeText.ts +42 -0
  145. package/ai/tools/category/createCategoryTool.ts +66 -0
  146. package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
  147. package/ai/tools/category/updateContentCategoryTool.ts +75 -0
  148. package/ai/tools/cfBrowserTools.ts +319 -0
  149. package/ai/tools/cfSpeechToTextTool.ts +49 -0
  150. package/ai/tools/checkEnvTool.ts +102 -0
  151. package/ai/tools/cloudflareCrawlTool.ts +289 -0
  152. package/ai/tools/codeSearchTool.ts +123 -0
  153. package/ai/tools/codeTools.ts +101 -0
  154. package/ai/tools/convertMarxistsBookTool.ts +103 -0
  155. package/ai/tools/createDocTool.ts +132 -0
  156. package/ai/tools/createSkillDocTool.ts +155 -0
  157. package/ai/tools/createWorkflowTool.ts +154 -0
  158. package/ai/tools/delayTool.ts +31 -0
  159. package/ai/tools/deleteSpacesTool.ts +325 -0
  160. package/ai/tools/deleteSpacesToolModel.ts +159 -0
  161. package/ai/tools/devReloadUtils.ts +29 -0
  162. package/ai/tools/dialogMessageSearch.ts +137 -0
  163. package/ai/tools/doctorSkillTool.ts +72 -0
  164. package/ai/tools/ecommerceScraperTool.ts +86 -0
  165. package/ai/tools/emailTools.ts +549 -0
  166. package/ai/tools/evalSkillTool.ts +92 -0
  167. package/ai/tools/exaSearchTool.ts +63 -0
  168. package/ai/tools/execShellTool.ts +266 -0
  169. package/ai/tools/executeSqlTool.ts +192 -0
  170. package/ai/tools/fetchWebpageSupport.ts +333 -0
  171. package/ai/tools/fetchWebpageTool.ts +97 -0
  172. package/ai/tools/geminiImagePreviewTool.ts +386 -0
  173. package/ai/tools/generateDocxTool.ts +215 -0
  174. package/ai/tools/googleSearchScraperTool.ts +106 -0
  175. package/ai/tools/importDataTool.ts +133 -0
  176. package/ai/tools/importSkillTool.ts +162 -0
  177. package/ai/tools/index.ts +2290 -0
  178. package/ai/tools/jdProductScraperTool.ts +821 -0
  179. package/ai/tools/listUserSpacesTool.ts +113 -0
  180. package/ai/tools/localFilesTool.ts +276 -0
  181. package/ai/tools/marxistsOfflineBook.ts +253 -0
  182. package/ai/tools/modelUsageTools.ts +206 -0
  183. package/ai/tools/noloWorkspaceReadTools.ts +467 -0
  184. package/ai/tools/olmOcrTool.ts +33 -0
  185. package/ai/tools/openaiImageTool.ts +267 -0
  186. package/ai/tools/prepareTools.ts +193 -0
  187. package/ai/tools/readDocTool.ts +88 -0
  188. package/ai/tools/readFileTool.ts +214 -0
  189. package/ai/tools/readTool.ts +194 -0
  190. package/ai/tools/readXPostTool.ts +229 -0
  191. package/ai/tools/readXhsProfileTool.ts +638 -0
  192. package/ai/tools/rememberMemoryTool.ts +84 -0
  193. package/ai/tools/remotionVideoTool.ts +151 -0
  194. package/ai/tools/searchDialogMessagesTool.ts +222 -0
  195. package/ai/tools/searchWorkspaceTool.ts +259 -0
  196. package/ai/tools/skillFollowup.ts +86 -0
  197. package/ai/tools/surfWeatherTool.ts +169 -0
  198. package/ai/tools/table/addTableRowTool.ts +217 -0
  199. package/ai/tools/table/createTableTool.ts +326 -0
  200. package/ai/tools/table/rowTools.ts +386 -0
  201. package/ai/tools/table/schemaTools.ts +244 -0
  202. package/ai/tools/table/shareTableTool.ts +148 -0
  203. package/ai/tools/table/toolShared.ts +129 -0
  204. package/ai/tools/taobaoTmallProductScraperTool.ts +49 -0
  205. package/ai/tools/toolApiClient.ts +279 -0
  206. package/ai/tools/toolPacks.ts +19 -0
  207. package/ai/tools/toolResultError.ts +42 -0
  208. package/ai/tools/toolRunSlice.ts +303 -0
  209. package/ai/tools/toolSchemaCompatibility.ts +53 -0
  210. package/ai/tools/uiAskChoiceTool.ts +104 -0
  211. package/ai/tools/updateContentTitleTool.ts +84 -0
  212. package/ai/tools/updateDocTool.ts +105 -0
  213. package/ai/tools/updateUserPreferenceProfileTool.ts +153 -0
  214. package/ai/tools/wereadGatewayTool.ts +152 -0
  215. package/ai/tools/whisperTool.ts +76 -0
  216. package/ai/tools/writeFileTool.ts +213 -0
  217. package/ai/tools/youtubeScraperTool.ts +116 -0
  218. package/ai/tools/ziweiChartTool.ts +678 -0
  219. package/ai/types.ts +58 -0
  220. package/ai/workflow/workflowExecutor.ts +323 -0
  221. package/ai/workflow/workflowSlice.ts +73 -0
  222. package/ai/workflow/workflowTypes.ts +106 -0
  223. package/app/actions/syncAppRecord.ts +73 -0
  224. package/app/constants/animationSets.ts +21 -0
  225. package/app/constants/appEditor.ts +99 -0
  226. package/app/favorite/deletedFavoriteProjection.ts +31 -0
  227. package/app/favorite/favoriteSlice.ts +690 -0
  228. package/app/favorite/type.ts +43 -0
  229. package/app/hooks/deleteDbKey.ts +254 -0
  230. package/app/i18n/client.ts +13 -0
  231. package/app/i18n/i18n.base.ts +14 -0
  232. package/app/i18n/i18n.config.ts +77 -0
  233. package/app/i18n/index.ts +15 -0
  234. package/app/i18n/mapLanguage.ts +11 -0
  235. package/app/i18n/translations/appBuilder.locale.ts +453 -0
  236. package/app/i18n/translations/error.locale.ts +246 -0
  237. package/app/i18n/translations/interface.locale.ts +2206 -0
  238. package/app/i18n/translations/pricing.locale.ts +397 -0
  239. package/app/i18n/translations/privacy.locale.ts +168 -0
  240. package/app/i18n/translations/seo.locale.ts +129 -0
  241. package/app/i18n/translations/terms.locale.ts +124 -0
  242. package/app/i18n/types.ts +6 -0
  243. package/app/notifications/model.ts +77 -0
  244. package/app/notifications/notificationSlice.ts +141 -0
  245. package/app/reducer.ts +36 -0
  246. package/app/settings/dbActionThunks.ts +34 -0
  247. package/app/settings/defaultSpacePreference.ts +87 -0
  248. package/app/settings/settingSlice.tsx +1212 -0
  249. package/app/settings/settingsRecord.ts +8 -0
  250. package/app/stateViews/runtime.ts +90 -0
  251. package/app/store.ts +55 -0
  252. package/app/theme/colors.ts +280 -0
  253. package/app/theme/fontPreference.ts +77 -0
  254. package/app/theme/theme.config.ts +120 -0
  255. package/app/theme/themeModeBootstrap.ts +123 -0
  256. package/app/types/appSummary.ts +118 -0
  257. package/app/types.ts +358 -0
  258. package/app/utils/appKeys.ts +55 -0
  259. package/app/utils/async.ts +28 -0
  260. package/app/utils/desktopAgentRuntimeTurnClient.ts +75 -0
  261. package/app/utils/env.ts +17 -0
  262. package/app/utils/fileUtils.ts +229 -0
  263. package/app/utils/imageUtils.ts +274 -0
  264. package/app/utils/myContentItems.ts +289 -0
  265. package/app/utils/retryAfter.ts +36 -0
  266. package/app/utils/retryFetch.ts +61 -0
  267. package/app/utils/toast.ts +3 -0
  268. package/auth/action/signUpAction.ts +227 -0
  269. package/auth/adminPermissions.ts +78 -0
  270. package/auth/authSlice.ts +531 -0
  271. package/auth/client/loginRequest.ts +14 -0
  272. package/auth/resetAuthScopedClientState.ts +27 -0
  273. package/auth/routes.ts +183 -0
  274. package/auth/token.ts +63 -0
  275. package/auth/types.ts +40 -0
  276. package/chat/chat.locale.ts +817 -0
  277. package/chat/dialog/actions/addCybotAction.ts +52 -0
  278. package/chat/dialog/actions/addReferenceKeysAction.ts +62 -0
  279. package/chat/dialog/actions/builtinDialogLlm.ts +35 -0
  280. package/chat/dialog/actions/cleanupCliSession.ts +40 -0
  281. package/chat/dialog/actions/createDialogAction.ts +379 -0
  282. package/chat/dialog/actions/createScheduledTaskAction.ts +78 -0
  283. package/chat/dialog/actions/handleSendMessageAction.ts +202 -0
  284. package/chat/dialog/actions/handleSendMessageResolver.ts +27 -0
  285. package/chat/dialog/actions/removeCybotAction.ts +6 -0
  286. package/chat/dialog/actions/removeDialogAgentAction.ts +44 -0
  287. package/chat/dialog/actions/replacePrimaryCybotAction.ts +6 -0
  288. package/chat/dialog/actions/setPrimaryDialogAgentAction.ts +52 -0
  289. package/chat/dialog/actions/updateDialogSummaryAction.ts +430 -0
  290. package/chat/dialog/actions/updateDialogTitleAction.ts +151 -0
  291. package/chat/dialog/actions/updateDialogTitlePolicy.ts +30 -0
  292. package/chat/dialog/actions/updateTokensAction.ts +233 -0
  293. package/chat/dialog/dialogAgents.ts +72 -0
  294. package/chat/dialog/dialogAttachmentCleanup.ts +135 -0
  295. package/chat/dialog/dialogSlice.ts +985 -0
  296. package/chat/dialog/dialogTitle.ts +81 -0
  297. package/chat/dialog/dialogTokenStats.ts +12 -0
  298. package/chat/dialog/dialogUrl.ts +6 -0
  299. package/chat/dialog/goal.ts +108 -0
  300. package/chat/dialog/objectAssistantRegistry.ts +286 -0
  301. package/chat/dialog/schedule.ts +17 -0
  302. package/chat/messages/activityCompletion.ts +97 -0
  303. package/chat/messages/fetchAndCacheMessages.ts +119 -0
  304. package/chat/messages/fetchConvMsgs.ts +51 -0
  305. package/chat/messages/fileUrl.ts +13 -0
  306. package/chat/messages/imagePayloadPersistence.ts +22 -0
  307. package/chat/messages/messageAgent.ts +8 -0
  308. package/chat/messages/messageContent.ts +203 -0
  309. package/chat/messages/messageContract.ts +88 -0
  310. package/chat/messages/messageSlice.ts +1386 -0
  311. package/chat/messages/toolThunks.ts +646 -0
  312. package/chat/messages/types.ts +8 -1
  313. package/chat/messages/web/toolDisplayName.ts +686 -0
  314. package/cli/agentAliases.ts +29 -9
  315. package/cli/agentInternalCommandEntries.ts +11 -3
  316. package/cli/agentMachineCommands.ts +1 -0
  317. package/cli/agentRecordCommands.ts +2 -2
  318. package/cli/agentRecordHelpers.ts +59 -6
  319. package/cli/agentRunCommand.ts +84 -19
  320. package/cli/client/agentRun.ts +92 -261
  321. package/cli/client/localRuntimeAdapter.ts +292 -50
  322. package/cli/commandRegistry.ts +7 -4
  323. package/cli/dialogAttachmentCleanup.ts +151 -0
  324. package/cli/dialogCommands.ts +163 -61
  325. package/cli/dialogInternalCommandEntries.ts +1 -1
  326. package/cli/docCreateCommands.ts +345 -0
  327. package/cli/docInternalCommandEntries.ts +11 -0
  328. package/cli/docPageHelpers.ts +80 -0
  329. package/cli/docSkillHelpers.ts +67 -0
  330. package/cli/docSpaceHelpers.ts +46 -0
  331. package/cli/internalCommandEntries.ts +4 -0
  332. package/cli/machineCommands.ts +18 -34
  333. package/cli/memoryCommands.ts +253 -0
  334. package/cli/memoryInternalCommandEntries.ts +9 -0
  335. package/cli/qoderUsageProbe.ts +252 -0
  336. package/cli/scriptCommandEntries.ts +0 -3
  337. package/cli/secretScan.ts +31 -0
  338. package/cli/tableCommands.ts +248 -13
  339. package/cli/workflowInternalCommandEntries.ts +2 -3
  340. package/client/agentRun.test.ts +119 -83
  341. package/client/agentRun.ts +92 -261
  342. package/client/localRuntimeAdapter.test.ts +894 -32
  343. package/client/localRuntimeAdapter.ts +292 -50
  344. package/commandRegistry.ts +7 -4
  345. package/connector-experimental/capabilities.ts +10 -9
  346. package/core/builtinAgents.ts +209 -0
  347. package/core/config.ts +15 -0
  348. package/core/crypto.ts +51 -0
  349. package/core/generateKeyPairFromSeedV1.ts +15 -0
  350. package/core/generateMainKey.ts +22 -0
  351. package/core/init.ts +41 -0
  352. package/core/localOrigins.ts +8 -0
  353. package/core/password.ts +13 -0
  354. package/core/prefix.ts +23 -0
  355. package/create/editor/transforms/fromMarkdown/index.ts +260 -0
  356. package/create/editor/transforms/fromMarkdown/inline.ts +285 -0
  357. package/create/editor/transforms/fromMarkdown/table.ts +130 -0
  358. package/create/editor/transforms/markdownToSlate.ts +24 -0
  359. package/create/editor/transforms/slateToRenderMarkdown.ts +218 -0
  360. package/create/editor/transforms/slateToSimplifiedMarkdown.ts +224 -0
  361. package/create/editor/transforms/slateToText.ts +33 -0
  362. package/create/editor/utils/slateUtils.ts +233 -0
  363. package/create/space/addSpaceAction.ts +193 -0
  364. package/create/space/category/categoryActions.ts +427 -0
  365. package/create/space/changeSpaceAction.ts +36 -0
  366. package/create/space/constants.ts +8 -0
  367. package/create/space/content/addContentAction.ts +116 -0
  368. package/create/space/content/contentThunks.ts +90 -0
  369. package/create/space/content/deleteContentFromSpaceAction.ts +187 -0
  370. package/create/space/content/deleteMultipleContentAction.ts +112 -0
  371. package/create/space/content/moveContentAction.ts +285 -0
  372. package/create/space/content/updateContentCategoryAction.ts +154 -0
  373. package/create/space/content/updateContentTitleAction.ts +151 -0
  374. package/create/space/content/uploadAndAddFileToSpaceAction.ts +98 -0
  375. package/create/space/contentKeyUtils.ts +117 -0
  376. package/create/space/deleteSpaceAction.ts +276 -0
  377. package/create/space/fetchSpaceAction.ts +70 -0
  378. package/create/space/fetchSpaceSidebarStateAction.ts +26 -0
  379. package/create/space/loadDefaultSpaceAction.ts +57 -0
  380. package/create/space/member/addMemberAction.ts +79 -0
  381. package/create/space/member/fetchUserSpaceMembershipsAction.ts +386 -0
  382. package/create/space/member/memberThunks.ts +47 -0
  383. package/create/space/member/removeMemberAction.ts +67 -0
  384. package/create/space/resolvePreferredSpaceId.ts +113 -0
  385. package/create/space/sidebarVisibleTypes.ts +260 -0
  386. package/create/space/space.locale.ts +1087 -0
  387. package/create/space/spaceAccess.ts +182 -0
  388. package/create/space/spaceCollapsedState.ts +54 -0
  389. package/create/space/spaceKeys.ts +65 -0
  390. package/create/space/spaceSlice.ts +328 -0
  391. package/create/space/spaceThunks.ts +410 -0
  392. package/create/space/types.ts +27 -0
  393. package/create/space/updateSpaceAction.ts +107 -0
  394. package/create/space/utils/permissions.ts +47 -0
  395. package/create/types.ts +21 -0
  396. package/database/actions/agentReadResolution.ts +33 -0
  397. package/database/actions/common.ts +243 -0
  398. package/database/actions/deleteFile.ts +40 -0
  399. package/database/actions/fileContent.ts +125 -0
  400. package/database/actions/patch.ts +155 -0
  401. package/database/actions/read.ts +358 -0
  402. package/database/actions/readAndWait.ts +260 -0
  403. package/database/actions/readRequestManager.ts +120 -0
  404. package/database/actions/readResolution.ts +125 -0
  405. package/database/actions/remove.ts +94 -0
  406. package/database/actions/replication.ts +477 -0
  407. package/database/actions/upload.ts +186 -0
  408. package/database/actions/upsert.ts +56 -0
  409. package/database/actions/write.ts +146 -0
  410. package/database/authority/ownerKey.ts +80 -0
  411. package/database/authority/recordAuthority.ts +67 -0
  412. package/database/authority/userAuthorityRegistry.ts +54 -0
  413. package/database/client/fetchUserData.ts +61 -0
  414. package/database/dbActionThunks.ts +1 -0
  415. package/database/dbSlice.ts +149 -0
  416. package/database/fileRing.ts +51 -0
  417. package/database/fileStorage.ts +232 -0
  418. package/database/fileUrl.ts +34 -0
  419. package/database/keys.ts +767 -0
  420. package/database/queryPrefixes.ts +14 -0
  421. package/database/requests.ts +443 -0
  422. package/database/runtimeServerContext.ts +54 -0
  423. package/database/tenantPlacement.ts +57 -0
  424. package/database/userPreferenceRegister.ts +131 -0
  425. package/database/utils/ulid.ts +1 -0
  426. package/dialogAttachmentCleanup.ts +151 -0
  427. package/dialogCommands.ts +163 -61
  428. package/dialogInternalCommandEntries.ts +1 -1
  429. package/docCreateCommands.ts +345 -0
  430. package/docInternalCommandEntries.ts +11 -0
  431. package/docPageHelpers.ts +80 -0
  432. package/docSkillHelpers.ts +67 -0
  433. package/docSpaceHelpers.ts +46 -0
  434. package/integrations/anthropic/anthropicModels.ts +47 -0
  435. package/integrations/deepseek/models.ts +37 -0
  436. package/integrations/google/models.ts +341 -0
  437. package/integrations/openai/chatCompletionStreamMode.ts +10 -0
  438. package/integrations/openai/filterAndCleanMessages.ts +284 -0
  439. package/integrations/openai/flexTier.ts +102 -0
  440. package/integrations/openai/generateOpenAIRequestBody.ts +271 -0
  441. package/integrations/openai/generateResponseRequestBody.ts +77 -0
  442. package/integrations/openai/models.ts +271 -0
  443. package/integrations/openai/providerBodyCompatibility.ts +23 -0
  444. package/integrations/openai/responsesHelpers.ts +297 -0
  445. package/integrations/x-reader/types.ts +109 -0
  446. package/integrations/xai/models.ts +13 -0
  447. package/integrations/xhs-reader/redaction.ts +68 -0
  448. package/integrations/xhs-reader/types.ts +277 -0
  449. package/integrations/xhs-reader/url.ts +80 -0
  450. package/internalCommandEntries.ts +4 -0
  451. package/machineCommands.ts +18 -34
  452. package/memoryCommands.ts +253 -0
  453. package/memoryInternalCommandEntries.ts +9 -0
  454. package/package.json +454 -9
  455. package/qoderUsageProbe.ts +252 -0
  456. package/render/contentIcon/types.ts +167 -0
  457. package/render/page/createPageAction.ts +183 -0
  458. package/render/page/docSlice.ts +495 -0
  459. package/render/page/types.ts +19 -0
  460. package/render/table/createTableAction.ts +274 -0
  461. package/render/table/deleteTableAction.ts +193 -0
  462. package/render/table/fetchAndCacheTableRows.ts +174 -0
  463. package/render/table/tableSlice.ts +1167 -0
  464. package/render/table/toolValueUtils.ts +363 -0
  465. package/render/table/types.ts +262 -0
  466. package/render/table/utils/tableSerialization.ts +50 -0
  467. package/scriptCommandEntries.ts +0 -3
  468. package/secretScan.ts +31 -0
  469. package/server/handlers/agentRun/types.ts +105 -0
  470. package/share/action.ts +225 -0
  471. package/share/helpers.ts +302 -0
  472. package/share/keys.ts +243 -0
  473. package/share/publicSharePolicy.ts +27 -0
  474. package/share/shareSlice.ts +53 -0
  475. package/share/types.ts +100 -0
  476. package/tableCommands.ts +248 -13
  477. package/workflowInternalCommandEntries.ts +2 -3
  478. package/ai/tools/agent/taskRunTool.ts +0 -112
  479. package/cli/client/taskRunPrompt.ts +0 -27
  480. package/cli/taskRunCommand.ts +0 -265
  481. package/client/taskRunPrompt.ts +0 -27
  482. package/taskRunCommand.ts +0 -265
@@ -0,0 +1,252 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+
5
+ export type QoderQuotaUsage = {
6
+ userId: string | null;
7
+ userType: string | null;
8
+ expiresAt: string | null;
9
+ expiresAtMs: number | null;
10
+ isQuotaExceeded: boolean | null;
11
+ totalUsagePercentage: number | null;
12
+ quota: {
13
+ total: number | null;
14
+ used: number | null;
15
+ remaining: number | null;
16
+ percentage: number | null;
17
+ unit: string | null;
18
+ };
19
+ source: "qoder-cli-log";
20
+ logPath?: string;
21
+ capturedAt?: string;
22
+ capturedAtMs?: number | null;
23
+ };
24
+
25
+ export type QoderUsageFreshness = "fresh" | "stale" | "uncertain";
26
+
27
+ export type QoderUsageProbeResult = {
28
+ ok: boolean;
29
+ provider: "qoder";
30
+ usage?: (QoderQuotaUsage & { logPath: string });
31
+ limitations?: string[];
32
+ freshness?: QoderUsageFreshness;
33
+ ageSeconds?: number | null;
34
+ staleThresholdSeconds?: number;
35
+ scannedLogCount?: number;
36
+ reason?: string;
37
+ error?: string;
38
+ };
39
+
40
+ const QUOTA_RESPONSE_MARKER = "/api/v2/quota/usage response:";
41
+
42
+ const asFiniteNumber = (value: unknown): number | null =>
43
+ typeof value === "number" && Number.isFinite(value) ? value : null;
44
+
45
+ const asString = (value: unknown): string | null =>
46
+ typeof value === "string" && value.trim() ? value.trim() : null;
47
+
48
+ const asBoolean = (value: unknown): boolean | null =>
49
+ typeof value === "boolean" ? value : null;
50
+
51
+ function normalizeQuotaPayload(payload: any): QoderQuotaUsage | null {
52
+ if (!payload || typeof payload !== "object") return null;
53
+ const quota = payload.userQuota && typeof payload.userQuota === "object"
54
+ ? payload.userQuota
55
+ : {};
56
+ const expiresAtMs = asFiniteNumber(payload.expiresAt);
57
+ return {
58
+ userId: asString(payload.userId),
59
+ userType: asString(payload.userType),
60
+ expiresAt: expiresAtMs != null ? new Date(expiresAtMs).toISOString() : null,
61
+ expiresAtMs,
62
+ isQuotaExceeded: asBoolean(payload.isQuotaExceeded),
63
+ totalUsagePercentage: asFiniteNumber(payload.totalUsagePercentage),
64
+ quota: {
65
+ total: asFiniteNumber(quota.total),
66
+ used: asFiniteNumber(quota.used),
67
+ remaining: asFiniteNumber(quota.remaining),
68
+ percentage: asFiniteNumber(quota.percentage),
69
+ unit: asString(quota.unit),
70
+ },
71
+ source: "qoder-cli-log",
72
+ };
73
+ }
74
+
75
+ function isRealQuotaResponseLine(line: string): boolean {
76
+ const markerIndex = line.indexOf(QUOTA_RESPONSE_MARKER);
77
+ if (markerIndex < 0) return false;
78
+ const before = line.slice(0, markerIndex);
79
+ if (!before.includes("[qoderApi]")) return false;
80
+ const jsonStart = markerIndex + QUOTA_RESPONSE_MARKER.length;
81
+ const after = line.slice(jsonStart).trimStart();
82
+ return after.startsWith("{");
83
+ }
84
+
85
+ export function parseQoderQuotaUsageFromText(text: string): QoderQuotaUsage | null {
86
+ let latest: QoderQuotaUsage | null = null;
87
+ for (const line of text.split(/\r?\n/)) {
88
+ if (!isRealQuotaResponseLine(line)) continue;
89
+ const markerIndex = line.indexOf(QUOTA_RESPONSE_MARKER);
90
+ const jsonText = line.slice(markerIndex + QUOTA_RESPONSE_MARKER.length).trim();
91
+ try {
92
+ const parsed = normalizeQuotaPayload(JSON.parse(jsonText));
93
+ if (parsed) latest = parsed;
94
+ } catch {
95
+ // Ignore malformed historical log lines.
96
+ }
97
+ }
98
+ return latest;
99
+ }
100
+
101
+ export function extractLeadingIsoTimestamp(dirName: string): string | null {
102
+ const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2})-(\d{2})-(\d{2})(?:-(\d{3}))?([+-])(\d{2})-(\d{2})/.exec(dirName);
103
+ if (!match) return null;
104
+ const [, Y, M, D, h, m, s, ms, sign, offH, offM] = match;
105
+ const local = Date.UTC(Number(Y), Number(M) - 1, Number(D), Number(h), Number(m), Number(s), Number(ms ?? 0));
106
+ const offsetMs = (Number(offH) * 60 + Number(offM)) * 60_000;
107
+ const utcMs = sign === "+" ? local - offsetMs : local + offsetMs;
108
+ if (!Number.isFinite(utcMs)) return null;
109
+ return new Date(utcMs).toISOString();
110
+ }
111
+
112
+ type RunLogEntry = {
113
+ logPath: string;
114
+ capturedAtMs: number | null;
115
+ capturedAt: string | null;
116
+ dirName: string;
117
+ };
118
+
119
+ function listQoderRunLogs(qoderHome: string): RunLogEntry[] {
120
+ const runsDir = join(qoderHome, "logs", "runs");
121
+ if (!existsSync(runsDir)) return [];
122
+ const entries: RunLogEntry[] = [];
123
+ for (const entry of readdirSync(runsDir, { withFileTypes: true })) {
124
+ if (!entry.isDirectory()) continue;
125
+ const logPath = join(runsDir, entry.name, "qodercli.log");
126
+ if (!existsSync(logPath)) continue;
127
+ const capturedAt = extractLeadingIsoTimestamp(entry.name);
128
+ const capturedAtMs = capturedAt ? Date.parse(capturedAt) : null;
129
+ entries.push({
130
+ logPath,
131
+ capturedAtMs,
132
+ capturedAt,
133
+ dirName: entry.name,
134
+ });
135
+ }
136
+ entries.sort((a, b) => {
137
+ const aMs = a.capturedAtMs ?? statSync(a.logPath).mtimeMs;
138
+ const bMs = b.capturedAtMs ?? statSync(b.logPath).mtimeMs;
139
+ return bMs - aMs;
140
+ });
141
+ return entries;
142
+ }
143
+
144
+ export function findLatestQoderQuotaUsage(options: {
145
+ qoderHome?: string;
146
+ now?: number;
147
+ } = {}): (QoderQuotaUsage & { logPath: string; capturedAtMs: number | null; capturedAt: string | null }) | null {
148
+ const qoderHome = options.qoderHome || join(homedir(), ".qoder");
149
+ for (const run of listQoderRunLogs(qoderHome)) {
150
+ const parsed = parseQoderQuotaUsageFromText(readFileSync(run.logPath, "utf8"));
151
+ if (!parsed) continue;
152
+ return {
153
+ ...parsed,
154
+ logPath: run.logPath,
155
+ capturedAt: run.capturedAt,
156
+ capturedAtMs: run.capturedAtMs,
157
+ };
158
+ }
159
+ return null;
160
+ }
161
+
162
+ const DEFAULT_STALE_THRESHOLD_SECONDS = 6 * 60 * 60;
163
+
164
+ export function classifyQoderUsageFreshness(
165
+ usage: { capturedAtMs: number | null } | null,
166
+ options: { now?: number; staleThresholdSeconds?: number } = {},
167
+ ): QoderUsageFreshness {
168
+ if (!usage || usage.capturedAtMs == null) return "uncertain";
169
+ const now = options.now ?? Date.now();
170
+ const threshold = (options.staleThresholdSeconds ?? DEFAULT_STALE_THRESHOLD_SECONDS) * 1000;
171
+ const age = now - usage.capturedAtMs;
172
+ if (!Number.isFinite(age) || age < 0) return "uncertain";
173
+ return age > threshold ? "stale" : "fresh";
174
+ }
175
+
176
+ function readOption(args: string[], flag: string) {
177
+ const index = args.indexOf(flag);
178
+ return index >= 0 ? args[index + 1] : undefined;
179
+ }
180
+
181
+ export async function runQoderUsageCommand(
182
+ args: string[],
183
+ deps: {
184
+ env?: Record<string, string | undefined>;
185
+ output?: { write(chunk: string): unknown };
186
+ now?: () => number;
187
+ } = {},
188
+ ) {
189
+ const output = deps.output ?? process.stdout;
190
+ const agent = args[0]?.trim();
191
+ if (!agent || agent === "--help" || agent === "-h") {
192
+ output.write("Usage: nolo agent usage qoder [--qoder-home <path>] [--stale-threshold-seconds <n>]\n");
193
+ return agent ? 0 : 1;
194
+ }
195
+ if (agent.toLowerCase() !== "qoder") {
196
+ output.write(`[nolo] agent usage currently supports qoder only, received ${agent}.\n`);
197
+ return 1;
198
+ }
199
+ const qoderHome =
200
+ readOption(args, "--qoder-home") ||
201
+ deps.env?.QODER_HOME ||
202
+ join(homedir(), ".qoder");
203
+ const now = deps.now ? deps.now() : Date.now();
204
+ const thresholdArg = readOption(args, "--stale-threshold-seconds");
205
+ const staleThresholdSeconds = thresholdArg ? Number(thresholdArg) : DEFAULT_STALE_THRESHOLD_SECONDS;
206
+ const usage = findLatestQoderQuotaUsage({ qoderHome, now });
207
+ const freshness = classifyQoderUsageFreshness(usage, { now, staleThresholdSeconds });
208
+ const ageSeconds = usage?.capturedAtMs != null ? Math.max(0, Math.floor((now - usage.capturedAtMs) / 1000)) : null;
209
+
210
+ if (!usage) {
211
+ const result: QoderUsageProbeResult = {
212
+ ok: false,
213
+ provider: "qoder",
214
+ freshness,
215
+ ageSeconds,
216
+ staleThresholdSeconds,
217
+ limitations: [
218
+ "This probe only reads Qoder package Credits from local quota logs.",
219
+ "It does not currently read the Qwen3.7-Max daily free request quota; check Qoder's Usage Overview or CLI /usage for that counter.",
220
+ ],
221
+ error:
222
+ "No Qoder quota usage log found. Open `qoder`, run `/usage`, then retry this command.",
223
+ reason:
224
+ "Probe could not locate any real [qoderApi] quota response line in local run logs.",
225
+ };
226
+ output.write(JSON.stringify(result, null, 2));
227
+ output.write("\n");
228
+ return 1;
229
+ }
230
+
231
+ const result: QoderUsageProbeResult = {
232
+ ok: true,
233
+ provider: "qoder",
234
+ usage,
235
+ limitations: [
236
+ "This is package Credits usage only, parsed from Qoder's /api/v2/quota/usage log.",
237
+ "Qwen3.7-Max daily free requests are a separate counter and are not exposed in this probe's current log source.",
238
+ ],
239
+ freshness,
240
+ ageSeconds,
241
+ staleThresholdSeconds,
242
+ };
243
+ if (freshness !== "fresh") {
244
+ result.reason =
245
+ freshness === "stale"
246
+ ? `Latest local quota log is ${ageSeconds}s old (threshold ${staleThresholdSeconds}s); UI or server may show a different value.`
247
+ : "Latest local quota log has no reliable capture timestamp; treat numbers as uncertain.";
248
+ }
249
+ output.write(JSON.stringify(result, null, 2));
250
+ output.write("\n");
251
+ return freshness === "fresh" ? 0 : 2;
252
+ }
@@ -0,0 +1,167 @@
1
+ export type ContentIcon =
2
+ | { kind: "emoji"; value: string }
3
+ | {
4
+ kind: "lucide";
5
+ value:
6
+ | "file-text"
7
+ | "table"
8
+ | "layout-grid"
9
+ | "star"
10
+ | "book"
11
+ | "image"
12
+ | "folder"
13
+ | "folder-kanban"
14
+ | "kanban"
15
+ | "layers"
16
+ | "notebook"
17
+ | "clipboard-list"
18
+ | "briefcase"
19
+ | "calendar"
20
+ | "clock"
21
+ | "list-todo"
22
+ | "chart-bar"
23
+ | "chart-line"
24
+ | "database"
25
+ | "code"
26
+ | "file-code"
27
+ | "terminal"
28
+ | "settings"
29
+ | "wrench"
30
+ | "pen-tool"
31
+ | "palette"
32
+ | "sparkles"
33
+ | "brain"
34
+ | "bot"
35
+ | "message-square"
36
+ | "users"
37
+ | "globe"
38
+ | "link"
39
+ | "bookmark"
40
+ | "heart"
41
+ | "flag"
42
+ | "zap"
43
+ | "lightbulb"
44
+ | "search"
45
+ | "map"
46
+ | "shopping-bag"
47
+ | "music"
48
+ | "video"
49
+ | "blocks"
50
+ | "flower"
51
+ | "flower-2"
52
+ | "leaf"
53
+ | "sprout"
54
+ | "tree-pine"
55
+ | "trees"
56
+ | "clover"
57
+ | "vegan"
58
+ | "bean"
59
+ | "wheat"
60
+ | "apple"
61
+ | "sun"
62
+ | "cloud-sun"
63
+ | "cloud-rain"
64
+ | "droplets"
65
+ | "mountain"
66
+ | "earth"
67
+ | "shell"
68
+ | "archive"
69
+ | "award"
70
+ | "badge-check"
71
+ | "bell"
72
+ | "box"
73
+ | "boxes"
74
+ | "cake"
75
+ | "camera"
76
+ | "circle-dollar-sign"
77
+ | "circle-help"
78
+ | "coffee"
79
+ | "compass"
80
+ | "cpu"
81
+ | "crown"
82
+ | "diamond"
83
+ | "dumbbell"
84
+ | "file-archive"
85
+ | "file-image"
86
+ | "file-spreadsheet"
87
+ | "file-type"
88
+ | "flask-conical"
89
+ | "gamepad-2"
90
+ | "gift"
91
+ | "graduation-cap"
92
+ | "hammer"
93
+ | "handshake"
94
+ | "headphones"
95
+ | "house"
96
+ | "key"
97
+ | "languages"
98
+ | "laptop"
99
+ | "library"
100
+ | "mail"
101
+ | "megaphone"
102
+ | "mic"
103
+ | "monitor"
104
+ | "moon"
105
+ | "newspaper"
106
+ | "package"
107
+ | "paperclip"
108
+ | "plane"
109
+ | "puzzle"
110
+ | "route"
111
+ | "shield"
112
+ | "smile"
113
+ | "tags"
114
+ | "target"
115
+ | "telescope"
116
+ | "ticket"
117
+ | "trophy"
118
+ | "wallet"
119
+ | "workflow"
120
+ | "alarm-clock"
121
+ | "atom"
122
+ | "banknote"
123
+ | "battery-charging"
124
+ | "bluetooth"
125
+ | "bug"
126
+ | "car"
127
+ | "circle-user"
128
+ | "cloud"
129
+ | "command"
130
+ | "construction"
131
+ | "contact"
132
+ | "copy"
133
+ | "download"
134
+ | "eraser"
135
+ | "film"
136
+ | "fingerprint"
137
+ | "flame"
138
+ | "gem"
139
+ | "hard-drive"
140
+ | "hospital"
141
+ | "map-pin"
142
+ | "medal"
143
+ | "mouse-pointer-2"
144
+ | "network"
145
+ | "paintbrush"
146
+ | "pencil"
147
+ | "printer"
148
+ | "qr-code"
149
+ | "radar"
150
+ | "receipt"
151
+ | "recycle"
152
+ | "scan-line"
153
+ | "school"
154
+ | "server"
155
+ | "ship"
156
+ | "siren"
157
+ | "sliders-horizontal"
158
+ | "smartphone"
159
+ | "snowflake"
160
+ | "store"
161
+ | "sunrise"
162
+ | "sunset"
163
+ | "timer"
164
+ | "truck"
165
+ | "umbrella"
166
+ | "wifi";
167
+ };
@@ -0,0 +1,183 @@
1
+ // 文件路径: render/page/createPageAction.ts
2
+ import { selectUserId } from "../../auth/authSlice";
3
+ import {
4
+ addContentToSpace,
5
+ selectCurrentSpaceId,
6
+ } from "../../create/space/spaceSlice";
7
+ import { createPageKey } from "../../database/keys";
8
+ import i18n from "../../app/i18n/client";
9
+ import { DataType } from "../../create/types";
10
+ import type { RootState, AppDispatch } from "../../app/store";
11
+ import { write } from "../../database/dbSlice";
12
+ import type { PageData } from "./types";
13
+ import { format } from "date-fns";
14
+
15
+ // 新增:把 markdown 转为 Slate 的工具 & 类型
16
+ import { markdownToSlate } from "../../create/editor/transforms/markdownToSlate";
17
+ import {
18
+ createEmptyParagraph,
19
+ splitSlateTitleAndBody,
20
+ type EditorContent,
21
+ } from "../../create/editor/utils/slateUtils";
22
+ import { slateToRenderMarkdown } from "../../create/editor/transforms/slateToRenderMarkdown";
23
+ import { parseSkillDocProtocol } from "../../ai/skills/skillDocProtocol";
24
+ import { buildSkillSummaryMarker } from "../../ai/skills/skillSummaryMarker";
25
+
26
+ /**
27
+ * 归一化 / 过滤 categoryId
28
+ *
29
+ * 设计目标:
30
+ * - 允许正常的、看起来像 ID 的字符串通过;
31
+ * - 对 AI 乱编的 “读书笔记分类” / “分类一” / 超短数字 等,直接当成 undefined。
32
+ *
33
+ * 注意:这里的规则可以按你实际的 ID 生成规则调整。
34
+ */
35
+ const normalizeCategoryId = (raw?: string): string | undefined => {
36
+ const trimmed = raw?.trim();
37
+ if (!trimmed) return undefined;
38
+
39
+ // 1) 过滤掉包含空格或非 ASCII 字符的情况
40
+ // 比如 “读书笔记分类” 会被直接判为无效
41
+ const asciiNoSpace = /^[\x20-\x7E]+$/; // 可见 ASCII 字符
42
+ if (!asciiNoSpace.test(trimmed)) return undefined;
43
+
44
+ // 2) 简单做个长度下限,避免 "1"、"abc" 这种明显不是 ID 的值
45
+ // 如果你的真实 ID 很短,可以把 8 调小一点
46
+ if (trimmed.length < 8) return undefined;
47
+
48
+ // 3) 如果你有更具体规则(如 UUID / nanoid),可以在这里再加一层匹配
49
+ // const idLike = /^[0-9a-zA-Z_-]{10,64}$/;
50
+ // if (!idLike.test(trimmed)) return undefined;
51
+
52
+ return trimmed;
53
+ };
54
+
55
+ export const createPageAction = async (
56
+ {
57
+ categoryId,
58
+ spaceId: customSpaceId,
59
+ title: initialTitle,
60
+ addMomentTag,
61
+ content,
62
+ slateData,
63
+ }: {
64
+ categoryId?: string;
65
+ spaceId?: string;
66
+ title?: string;
67
+ addMomentTag?: boolean;
68
+ content?: string; // 这里仍然接收 markdown 文本
69
+ slateData?: any; // 如果外部已经算好 Slate,可以直接传进来
70
+ } = {},
71
+ { dispatch, getState }: { dispatch: AppDispatch; getState: () => RootState }
72
+ ): Promise<string> => {
73
+ const state = getState();
74
+ const userId = selectUserId(state);
75
+ if (!userId) throw new Error("User ID not found.");
76
+
77
+ // Important:
78
+ // View-mode-based "create into current space vs no space" is decided by the UI entry
79
+ // that triggers creation (currently the sidebar-top create button).
80
+ // This action must preserve explicit caller intent:
81
+ // - if `spaceId` is provided, use it;
82
+ // - otherwise only fall back to the current selected space.
83
+ const spaceId = customSpaceId ?? selectCurrentSpaceId(state);
84
+ const { dbKey, id } = createPageKey.create(userId);
85
+
86
+ const now = new Date();
87
+ const dateStr = format(now, "yyyy-MM-dd HH:mm");
88
+ const defaultTitle = i18n.t("page:defaultTitleFormat", {
89
+ defaultValue: "{{date}} 的笔记",
90
+ date: dateStr,
91
+ });
92
+ let title = initialTitle?.trim() || defaultTitle;
93
+
94
+ const tags = addMomentTag ? ["moment"] : undefined;
95
+ let pageMeta: PageData["meta"] | undefined;
96
+
97
+ // ====== 根据 slateData / content 决定真正写入的 Slate 结构 ======
98
+ let initialSlateData: EditorContent;
99
+
100
+ if (slateData) {
101
+ // 1. 如果外部已经传了 Slate,直接使用(兼容旧调用)
102
+ initialSlateData = slateData as EditorContent;
103
+ } else if (content) {
104
+ const parsedProtocol = parseSkillDocProtocol(content);
105
+ const normalizedContent = parsedProtocol.content;
106
+ pageMeta = parsedProtocol.meta;
107
+ console.log("content", content);
108
+ // 2. 如果有 markdown content,优先尝试用 markdownToSlate 转成结构化 Slate
109
+ try {
110
+ const parsed = markdownToSlate(normalizedContent);
111
+ console.log("parsed", parsed);
112
+
113
+ if (Array.isArray(parsed) && parsed.length > 0) {
114
+ const split = splitSlateTitleAndBody(parsed, initialTitle);
115
+ title = initialTitle?.trim() || split.title || defaultTitle;
116
+ initialSlateData = split.body;
117
+ } else {
118
+ // 解析结果为空时,退回到简单的纯文本段落
119
+ initialSlateData = [
120
+ { type: "paragraph", children: [{ text: normalizedContent }] },
121
+ ];
122
+ }
123
+ } catch (e) {
124
+ // 解析失败兜底:仍然保留原始文本,但当成普通段落
125
+ console.error(
126
+ "[createPageAction] markdownToSlate failed, fallback to plain text:",
127
+ e
128
+ );
129
+ initialSlateData = [
130
+ { type: "paragraph", children: [{ text: normalizedContent }] },
131
+ ];
132
+ }
133
+ } else {
134
+ // 3. 完全没有内容,创建一个空白页面
135
+ initialSlateData = [createEmptyParagraph()];
136
+ }
137
+ // ====== 关键改动结束 ======
138
+
139
+ // 关键防御:对传入的 categoryId 做归一化 / 过滤
140
+ const safeCategoryId = normalizeCategoryId(categoryId);
141
+
142
+ const pageData: PageData = {
143
+ dbKey,
144
+ id,
145
+ type: DataType.DOC,
146
+ title,
147
+ spaceId,
148
+ slateData: initialSlateData,
149
+ // `content` 只作为只读展示缓存 / legacy bridge,真源仍是 `slateData`。
150
+ content:
151
+ typeof content === "string"
152
+ ? parseSkillDocProtocol(content, pageMeta).content ||
153
+ slateToRenderMarkdown(initialSlateData)
154
+ : slateToRenderMarkdown(initialSlateData),
155
+ tags,
156
+ created: now.toISOString(),
157
+ ...(pageMeta ? { meta: pageMeta } : {}),
158
+ };
159
+
160
+ const skillSummary = buildSkillSummaryMarker(pageMeta);
161
+
162
+ await dispatch(write({ data: pageData, customKey: dbKey })).unwrap();
163
+
164
+ if (spaceId) {
165
+ (dispatch as any)(
166
+ (addContentToSpace as any)({
167
+ contentKey: dbKey,
168
+ type: DataType.DOC,
169
+ spaceId,
170
+ title,
171
+ // 只使用经过 normalize 的 safeCategoryId
172
+ categoryId: safeCategoryId,
173
+ ...(skillSummary ? { skillSummary } : {}),
174
+ })
175
+ );
176
+ }
177
+
178
+ if (typeof window !== "undefined") {
179
+ window.dispatchEvent(new Event("nolo-user-data-updated"));
180
+ }
181
+
182
+ return dbKey;
183
+ };