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.
- package/README.md +27 -12
- package/agent-runtime/agentThread.ts +222 -0
- package/agent-runtime/agentThreadAdmission.ts +74 -0
- package/agent-runtime/dialogWritePlan.ts +42 -0
- package/agent-runtime/hostAdapter.ts +1 -0
- package/agent-runtime/hybridRecordStore.ts +5 -3
- package/agent-runtime/index.ts +43 -0
- package/agent-runtime/localLoop.ts +31 -2
- package/agent-runtime/localToolPolicy.ts +1 -0
- package/agent-runtime/localWorkspaceTools.ts +1258 -78
- package/agent-runtime/noloWorkspaceTools.ts +20 -1
- package/agent-runtime/runtimeToolPolicy.ts +1 -5
- package/agent-runtime/runtimeToolSurface.ts +1 -0
- package/agentAliases.ts +29 -9
- package/agentInternalCommandEntries.ts +11 -3
- package/agentMachineCommands.ts +1 -0
- package/agentRecordCommands.ts +2 -2
- package/agentRecordHelpers.ts +59 -6
- package/agentRunCommand.ts +84 -19
- package/ai/agent/_executeModel.ts +146 -0
- package/ai/agent/agentSlice.ts +556 -1
- package/ai/agent/appWorkingMemory.ts +126 -0
- package/ai/agent/buildEditingContext.ts +378 -0
- package/ai/agent/buildSystemPrompt.ts +599 -0
- package/ai/agent/canvasEditingContext.ts +49 -0
- package/ai/agent/cleanAgentMessages.ts +140 -0
- package/ai/agent/cliChatClient.ts +153 -0
- package/ai/agent/cliExecutor.ts +264 -46
- package/ai/agent/contextCompiler.ts +107 -0
- package/ai/agent/contextLayerContract.ts +44 -0
- package/ai/agent/createAgentSchema.ts +272 -0
- package/ai/agent/currentTimeContext.ts +65 -0
- package/ai/agent/executeToolCall.ts +58 -0
- package/ai/agent/fetchAgentContexts.ts +42 -0
- package/ai/agent/generatePrompt.ts +3 -0
- package/ai/agent/getFullChatContextKeys.ts +168 -0
- package/ai/agent/guidedCreation/capabilities.ts +84 -0
- package/ai/agent/guidedCreation/types.ts +38 -0
- package/ai/agent/isLiveAudioOnlyAgent.ts +26 -0
- package/ai/agent/liveAudioModel.ts +2 -0
- package/ai/agent/pageBuilderHandoffRules.ts +75 -0
- package/ai/agent/persistMessageWithFixedId.ts +37 -0
- package/ai/agent/planSlice.ts +259 -0
- package/ai/agent/referenceUtils.ts +229 -0
- package/ai/agent/runAgentBackground.ts +310 -0
- package/ai/agent/runAgentClientLoop.ts +164 -0
- package/ai/agent/runtimeGuidance.ts +116 -0
- package/ai/agent/serverOrigin.ts +7 -0
- package/ai/agent/startParallelAgentStreams.ts +424 -0
- package/ai/agent/startupProtocol.ts +53 -0
- package/ai/agent/streamAgentChatTurn.ts +2135 -0
- package/ai/agent/streamAgentChatTurnUtils.ts +923 -0
- package/ai/agent/toolFailureGuard.ts +99 -0
- package/ai/agent/types.ts +73 -0
- package/ai/agent/utils/imageOutput.ts +37 -0
- package/ai/agent/utils/publicImageAgentMode.ts +26 -0
- package/ai/ai.locale.ts +1165 -0
- package/ai/chat/accumulateToolCallChunks.ts +126 -0
- package/ai/chat/fetchUtils.ts +143 -0
- package/ai/chat/inlineImageUrlsForCustomProvider.ts +122 -0
- package/ai/chat/parseApiError.ts +67 -0
- package/ai/chat/parseMultilineSSE.ts +95 -0
- package/ai/chat/sendOpenAICompletionsRequest.ts +921 -0
- package/ai/chat/sendOpenAIResponseRequest.ts +720 -0
- package/ai/chat/serverProxyRetry.ts +102 -0
- package/ai/chat/shouldUseServerProxy.ts +18 -0
- package/ai/chat/streamRetry.ts +46 -0
- package/ai/chat/updateTotalUsage.ts +89 -0
- package/ai/context/buildReferenceContext.ts +437 -0
- package/ai/context/retention.ts +165 -0
- package/ai/context/tokenUtils.ts +78 -0
- package/ai/llm/agentCapabilities.ts +74 -0
- package/ai/llm/deepinfra.ts +79 -0
- package/ai/llm/fireworks.ts +68 -0
- package/ai/llm/generateRequestBody.ts +165 -0
- package/ai/llm/getModelContextWindow.ts +93 -0
- package/ai/llm/getPricing.ts +252 -0
- package/ai/llm/imagePricing.ts +66 -0
- package/ai/llm/isResponseAPIModel.ts +13 -0
- package/ai/llm/kimi.ts +22 -0
- package/ai/llm/mimo.ts +99 -0
- package/ai/llm/mistral.ts +21 -0
- package/ai/llm/models.ts +45 -0
- package/ai/llm/openrouterModels.ts +31 -0
- package/ai/llm/providers.ts +313 -0
- package/ai/llm/reasoningModels.ts +27 -0
- package/ai/llm/types.ts +82 -0
- package/ai/llm/usageRequestOptions.ts +59 -0
- package/ai/memory/policy.ts +49 -0
- package/ai/memory/queryShared.ts +167 -0
- package/ai/memory/recentRelationshipRecap.ts +251 -0
- package/ai/memory/remember.ts +111 -0
- package/ai/memory/scope.ts +74 -0
- package/ai/memory/store.ts +20 -0
- package/ai/memory/storeShared.ts +76 -0
- package/ai/memory/types.ts +52 -0
- package/ai/memory/understanding.ts +341 -0
- package/ai/memory/understandingGreeting.ts +264 -0
- package/ai/policy/personalizationDialog.ts +333 -0
- package/ai/policy/runtimePolicy.ts +526 -0
- package/ai/policy/selfUpdateFields.ts +48 -0
- package/ai/policy/types.ts +64 -0
- package/ai/skills/referenceRuntime.ts +274 -0
- package/ai/skills/skillDiagnostics.ts +251 -0
- package/ai/skills/skillDocBuilder.ts +139 -0
- package/ai/skills/skillSummaryMarker.ts +26 -0
- package/ai/token/calculatePrice.ts +576 -0
- package/ai/token/missingUsageEstimate.ts +42 -0
- package/ai/token/normalizeUsage.ts +124 -0
- package/ai/token/openaiImageGenerationUsage.ts +56 -0
- package/ai/token/prepareTokenUsageData.ts +93 -0
- package/ai/token/resolveBillingTarget.ts +52 -0
- package/ai/token/saveTokenRecord.ts +53 -0
- package/ai/token/types.ts +103 -0
- package/ai/tools/agent/agentTools.ts +214 -0
- package/ai/tools/agent/agentUpdateShared.ts +311 -0
- package/ai/tools/agent/callAgentTool.ts +139 -0
- package/ai/tools/agent/createAgentTool.ts +512 -0
- package/ai/tools/agent/createDialogTool.ts +69 -0
- package/ai/tools/agent/createSkillAgentTool.ts +62 -0
- package/ai/tools/agent/parallelBudget.ts +221 -0
- package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
- package/ai/tools/agent/presets/appBuilderPreset.ts +154 -0
- package/ai/tools/agent/runLlmTool.ts +96 -0
- package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
- package/ai/tools/agent/skillAgentArgs.ts +106 -0
- package/ai/tools/agent/startAgentDialogTool.ts +54 -0
- package/ai/tools/agent/streamParallelAgentsTool.ts +123 -0
- package/ai/tools/agent/updateAgentTool.ts +96 -0
- package/ai/tools/agent/updateSelfTool.ts +113 -0
- package/ai/tools/amazonProductScraperTool.ts +86 -0
- package/ai/tools/apifyActorClient.ts +45 -0
- package/ai/tools/appEditGuard.ts +372 -0
- package/ai/tools/appReadSnapshot.ts +153 -0
- package/ai/tools/appTools.ts +1549 -0
- package/ai/tools/applyEditTool.ts +259 -0
- package/ai/tools/applyLineEditsTool.ts +315 -0
- package/ai/tools/browserTools/click.ts +33 -0
- package/ai/tools/browserTools/closeSession.ts +29 -0
- package/ai/tools/browserTools/common.ts +27 -0
- package/ai/tools/browserTools/openSession.ts +48 -0
- package/ai/tools/browserTools/readContent.ts +38 -0
- package/ai/tools/browserTools/selectOption.ts +46 -0
- package/ai/tools/browserTools/typeText.ts +42 -0
- package/ai/tools/category/createCategoryTool.ts +66 -0
- package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
- package/ai/tools/category/updateContentCategoryTool.ts +75 -0
- package/ai/tools/cfBrowserTools.ts +319 -0
- package/ai/tools/cfSpeechToTextTool.ts +49 -0
- package/ai/tools/checkEnvTool.ts +102 -0
- package/ai/tools/cloudflareCrawlTool.ts +289 -0
- package/ai/tools/codeSearchTool.ts +123 -0
- package/ai/tools/codeTools.ts +101 -0
- package/ai/tools/convertMarxistsBookTool.ts +103 -0
- package/ai/tools/createDocTool.ts +132 -0
- package/ai/tools/createSkillDocTool.ts +155 -0
- package/ai/tools/createWorkflowTool.ts +154 -0
- package/ai/tools/delayTool.ts +31 -0
- package/ai/tools/deleteSpacesTool.ts +325 -0
- package/ai/tools/deleteSpacesToolModel.ts +159 -0
- package/ai/tools/devReloadUtils.ts +29 -0
- package/ai/tools/dialogMessageSearch.ts +137 -0
- package/ai/tools/doctorSkillTool.ts +72 -0
- package/ai/tools/ecommerceScraperTool.ts +86 -0
- package/ai/tools/emailTools.ts +549 -0
- package/ai/tools/evalSkillTool.ts +92 -0
- package/ai/tools/exaSearchTool.ts +63 -0
- package/ai/tools/execShellTool.ts +266 -0
- package/ai/tools/executeSqlTool.ts +192 -0
- package/ai/tools/fetchWebpageSupport.ts +333 -0
- package/ai/tools/fetchWebpageTool.ts +97 -0
- package/ai/tools/geminiImagePreviewTool.ts +386 -0
- package/ai/tools/generateDocxTool.ts +215 -0
- package/ai/tools/googleSearchScraperTool.ts +106 -0
- package/ai/tools/importDataTool.ts +133 -0
- package/ai/tools/importSkillTool.ts +162 -0
- package/ai/tools/index.ts +2290 -0
- package/ai/tools/jdProductScraperTool.ts +821 -0
- package/ai/tools/listUserSpacesTool.ts +113 -0
- package/ai/tools/localFilesTool.ts +276 -0
- package/ai/tools/marxistsOfflineBook.ts +253 -0
- package/ai/tools/modelUsageTools.ts +206 -0
- package/ai/tools/noloWorkspaceReadTools.ts +467 -0
- package/ai/tools/olmOcrTool.ts +33 -0
- package/ai/tools/openaiImageTool.ts +267 -0
- package/ai/tools/prepareTools.ts +193 -0
- package/ai/tools/readDocTool.ts +88 -0
- package/ai/tools/readFileTool.ts +214 -0
- package/ai/tools/readTool.ts +194 -0
- package/ai/tools/readXPostTool.ts +229 -0
- package/ai/tools/readXhsProfileTool.ts +638 -0
- package/ai/tools/rememberMemoryTool.ts +84 -0
- package/ai/tools/remotionVideoTool.ts +151 -0
- package/ai/tools/searchDialogMessagesTool.ts +222 -0
- package/ai/tools/searchWorkspaceTool.ts +259 -0
- package/ai/tools/skillFollowup.ts +86 -0
- package/ai/tools/surfWeatherTool.ts +169 -0
- package/ai/tools/table/addTableRowTool.ts +217 -0
- package/ai/tools/table/createTableTool.ts +326 -0
- package/ai/tools/table/rowTools.ts +386 -0
- package/ai/tools/table/schemaTools.ts +244 -0
- package/ai/tools/table/shareTableTool.ts +148 -0
- package/ai/tools/table/toolShared.ts +129 -0
- package/ai/tools/taobaoTmallProductScraperTool.ts +49 -0
- package/ai/tools/toolApiClient.ts +279 -0
- package/ai/tools/toolPacks.ts +19 -0
- package/ai/tools/toolResultError.ts +42 -0
- package/ai/tools/toolRunSlice.ts +303 -0
- package/ai/tools/toolSchemaCompatibility.ts +53 -0
- package/ai/tools/uiAskChoiceTool.ts +104 -0
- package/ai/tools/updateContentTitleTool.ts +84 -0
- package/ai/tools/updateDocTool.ts +105 -0
- package/ai/tools/updateUserPreferenceProfileTool.ts +153 -0
- package/ai/tools/wereadGatewayTool.ts +152 -0
- package/ai/tools/whisperTool.ts +76 -0
- package/ai/tools/writeFileTool.ts +213 -0
- package/ai/tools/youtubeScraperTool.ts +116 -0
- package/ai/tools/ziweiChartTool.ts +678 -0
- package/ai/types.ts +58 -0
- package/ai/workflow/workflowExecutor.ts +323 -0
- package/ai/workflow/workflowSlice.ts +73 -0
- package/ai/workflow/workflowTypes.ts +106 -0
- package/app/actions/syncAppRecord.ts +73 -0
- package/app/constants/animationSets.ts +21 -0
- package/app/constants/appEditor.ts +99 -0
- package/app/favorite/deletedFavoriteProjection.ts +31 -0
- package/app/favorite/favoriteSlice.ts +690 -0
- package/app/favorite/type.ts +43 -0
- package/app/hooks/deleteDbKey.ts +254 -0
- package/app/i18n/client.ts +13 -0
- package/app/i18n/i18n.base.ts +14 -0
- package/app/i18n/i18n.config.ts +77 -0
- package/app/i18n/index.ts +15 -0
- package/app/i18n/mapLanguage.ts +11 -0
- package/app/i18n/translations/appBuilder.locale.ts +453 -0
- package/app/i18n/translations/error.locale.ts +246 -0
- package/app/i18n/translations/interface.locale.ts +2206 -0
- package/app/i18n/translations/pricing.locale.ts +397 -0
- package/app/i18n/translations/privacy.locale.ts +168 -0
- package/app/i18n/translations/seo.locale.ts +129 -0
- package/app/i18n/translations/terms.locale.ts +124 -0
- package/app/i18n/types.ts +6 -0
- package/app/notifications/model.ts +77 -0
- package/app/notifications/notificationSlice.ts +141 -0
- package/app/reducer.ts +36 -0
- package/app/settings/dbActionThunks.ts +34 -0
- package/app/settings/defaultSpacePreference.ts +87 -0
- package/app/settings/settingSlice.tsx +1212 -0
- package/app/settings/settingsRecord.ts +8 -0
- package/app/stateViews/runtime.ts +90 -0
- package/app/store.ts +55 -0
- package/app/theme/colors.ts +280 -0
- package/app/theme/fontPreference.ts +77 -0
- package/app/theme/theme.config.ts +120 -0
- package/app/theme/themeModeBootstrap.ts +123 -0
- package/app/types/appSummary.ts +118 -0
- package/app/types.ts +358 -0
- package/app/utils/appKeys.ts +55 -0
- package/app/utils/async.ts +28 -0
- package/app/utils/desktopAgentRuntimeTurnClient.ts +75 -0
- package/app/utils/env.ts +17 -0
- package/app/utils/fileUtils.ts +229 -0
- package/app/utils/imageUtils.ts +274 -0
- package/app/utils/myContentItems.ts +289 -0
- package/app/utils/retryAfter.ts +36 -0
- package/app/utils/retryFetch.ts +61 -0
- package/app/utils/toast.ts +3 -0
- package/auth/action/signUpAction.ts +227 -0
- package/auth/adminPermissions.ts +78 -0
- package/auth/authSlice.ts +531 -0
- package/auth/client/loginRequest.ts +14 -0
- package/auth/resetAuthScopedClientState.ts +27 -0
- package/auth/routes.ts +183 -0
- package/auth/token.ts +63 -0
- package/auth/types.ts +40 -0
- package/chat/chat.locale.ts +817 -0
- package/chat/dialog/actions/addCybotAction.ts +52 -0
- package/chat/dialog/actions/addReferenceKeysAction.ts +62 -0
- package/chat/dialog/actions/builtinDialogLlm.ts +35 -0
- package/chat/dialog/actions/cleanupCliSession.ts +40 -0
- package/chat/dialog/actions/createDialogAction.ts +379 -0
- package/chat/dialog/actions/createScheduledTaskAction.ts +78 -0
- package/chat/dialog/actions/handleSendMessageAction.ts +202 -0
- package/chat/dialog/actions/handleSendMessageResolver.ts +27 -0
- package/chat/dialog/actions/removeCybotAction.ts +6 -0
- package/chat/dialog/actions/removeDialogAgentAction.ts +44 -0
- package/chat/dialog/actions/replacePrimaryCybotAction.ts +6 -0
- package/chat/dialog/actions/setPrimaryDialogAgentAction.ts +52 -0
- package/chat/dialog/actions/updateDialogSummaryAction.ts +430 -0
- package/chat/dialog/actions/updateDialogTitleAction.ts +151 -0
- package/chat/dialog/actions/updateDialogTitlePolicy.ts +30 -0
- package/chat/dialog/actions/updateTokensAction.ts +233 -0
- package/chat/dialog/dialogAgents.ts +72 -0
- package/chat/dialog/dialogAttachmentCleanup.ts +135 -0
- package/chat/dialog/dialogSlice.ts +985 -0
- package/chat/dialog/dialogTitle.ts +81 -0
- package/chat/dialog/dialogTokenStats.ts +12 -0
- package/chat/dialog/dialogUrl.ts +6 -0
- package/chat/dialog/goal.ts +108 -0
- package/chat/dialog/objectAssistantRegistry.ts +286 -0
- package/chat/dialog/schedule.ts +17 -0
- package/chat/messages/activityCompletion.ts +97 -0
- package/chat/messages/fetchAndCacheMessages.ts +119 -0
- package/chat/messages/fetchConvMsgs.ts +51 -0
- package/chat/messages/fileUrl.ts +13 -0
- package/chat/messages/imagePayloadPersistence.ts +22 -0
- package/chat/messages/messageAgent.ts +8 -0
- package/chat/messages/messageContent.ts +203 -0
- package/chat/messages/messageContract.ts +88 -0
- package/chat/messages/messageSlice.ts +1386 -0
- package/chat/messages/toolThunks.ts +646 -0
- package/chat/messages/types.ts +8 -1
- package/chat/messages/web/toolDisplayName.ts +686 -0
- package/cli/agentAliases.ts +29 -9
- package/cli/agentInternalCommandEntries.ts +11 -3
- package/cli/agentMachineCommands.ts +1 -0
- package/cli/agentRecordCommands.ts +2 -2
- package/cli/agentRecordHelpers.ts +59 -6
- package/cli/agentRunCommand.ts +84 -19
- package/cli/client/agentRun.ts +92 -261
- package/cli/client/localRuntimeAdapter.ts +292 -50
- package/cli/commandRegistry.ts +7 -4
- package/cli/dialogAttachmentCleanup.ts +151 -0
- package/cli/dialogCommands.ts +163 -61
- package/cli/dialogInternalCommandEntries.ts +1 -1
- package/cli/docCreateCommands.ts +345 -0
- package/cli/docInternalCommandEntries.ts +11 -0
- package/cli/docPageHelpers.ts +80 -0
- package/cli/docSkillHelpers.ts +67 -0
- package/cli/docSpaceHelpers.ts +46 -0
- package/cli/internalCommandEntries.ts +4 -0
- package/cli/machineCommands.ts +18 -34
- package/cli/memoryCommands.ts +253 -0
- package/cli/memoryInternalCommandEntries.ts +9 -0
- package/cli/qoderUsageProbe.ts +252 -0
- package/cli/scriptCommandEntries.ts +0 -3
- package/cli/secretScan.ts +31 -0
- package/cli/tableCommands.ts +248 -13
- package/cli/workflowInternalCommandEntries.ts +2 -3
- package/client/agentRun.test.ts +119 -83
- package/client/agentRun.ts +92 -261
- package/client/localRuntimeAdapter.test.ts +894 -32
- package/client/localRuntimeAdapter.ts +292 -50
- package/commandRegistry.ts +7 -4
- package/connector-experimental/capabilities.ts +10 -9
- package/core/builtinAgents.ts +209 -0
- package/core/config.ts +15 -0
- package/core/crypto.ts +51 -0
- package/core/generateKeyPairFromSeedV1.ts +15 -0
- package/core/generateMainKey.ts +22 -0
- package/core/init.ts +41 -0
- package/core/localOrigins.ts +8 -0
- package/core/password.ts +13 -0
- package/core/prefix.ts +23 -0
- package/create/editor/transforms/fromMarkdown/index.ts +260 -0
- package/create/editor/transforms/fromMarkdown/inline.ts +285 -0
- package/create/editor/transforms/fromMarkdown/table.ts +130 -0
- package/create/editor/transforms/markdownToSlate.ts +24 -0
- package/create/editor/transforms/slateToRenderMarkdown.ts +218 -0
- package/create/editor/transforms/slateToSimplifiedMarkdown.ts +224 -0
- package/create/editor/transforms/slateToText.ts +33 -0
- package/create/editor/utils/slateUtils.ts +233 -0
- package/create/space/addSpaceAction.ts +193 -0
- package/create/space/category/categoryActions.ts +427 -0
- package/create/space/changeSpaceAction.ts +36 -0
- package/create/space/constants.ts +8 -0
- package/create/space/content/addContentAction.ts +116 -0
- package/create/space/content/contentThunks.ts +90 -0
- package/create/space/content/deleteContentFromSpaceAction.ts +187 -0
- package/create/space/content/deleteMultipleContentAction.ts +112 -0
- package/create/space/content/moveContentAction.ts +285 -0
- package/create/space/content/updateContentCategoryAction.ts +154 -0
- package/create/space/content/updateContentTitleAction.ts +151 -0
- package/create/space/content/uploadAndAddFileToSpaceAction.ts +98 -0
- package/create/space/contentKeyUtils.ts +117 -0
- package/create/space/deleteSpaceAction.ts +276 -0
- package/create/space/fetchSpaceAction.ts +70 -0
- package/create/space/fetchSpaceSidebarStateAction.ts +26 -0
- package/create/space/loadDefaultSpaceAction.ts +57 -0
- package/create/space/member/addMemberAction.ts +79 -0
- package/create/space/member/fetchUserSpaceMembershipsAction.ts +386 -0
- package/create/space/member/memberThunks.ts +47 -0
- package/create/space/member/removeMemberAction.ts +67 -0
- package/create/space/resolvePreferredSpaceId.ts +113 -0
- package/create/space/sidebarVisibleTypes.ts +260 -0
- package/create/space/space.locale.ts +1087 -0
- package/create/space/spaceAccess.ts +182 -0
- package/create/space/spaceCollapsedState.ts +54 -0
- package/create/space/spaceKeys.ts +65 -0
- package/create/space/spaceSlice.ts +328 -0
- package/create/space/spaceThunks.ts +410 -0
- package/create/space/types.ts +27 -0
- package/create/space/updateSpaceAction.ts +107 -0
- package/create/space/utils/permissions.ts +47 -0
- package/create/types.ts +21 -0
- package/database/actions/agentReadResolution.ts +33 -0
- package/database/actions/common.ts +243 -0
- package/database/actions/deleteFile.ts +40 -0
- package/database/actions/fileContent.ts +125 -0
- package/database/actions/patch.ts +155 -0
- package/database/actions/read.ts +358 -0
- package/database/actions/readAndWait.ts +260 -0
- package/database/actions/readRequestManager.ts +120 -0
- package/database/actions/readResolution.ts +125 -0
- package/database/actions/remove.ts +94 -0
- package/database/actions/replication.ts +477 -0
- package/database/actions/upload.ts +186 -0
- package/database/actions/upsert.ts +56 -0
- package/database/actions/write.ts +146 -0
- package/database/authority/ownerKey.ts +80 -0
- package/database/authority/recordAuthority.ts +67 -0
- package/database/authority/userAuthorityRegistry.ts +54 -0
- package/database/client/fetchUserData.ts +61 -0
- package/database/dbActionThunks.ts +1 -0
- package/database/dbSlice.ts +149 -0
- package/database/fileRing.ts +51 -0
- package/database/fileStorage.ts +232 -0
- package/database/fileUrl.ts +34 -0
- package/database/keys.ts +767 -0
- package/database/queryPrefixes.ts +14 -0
- package/database/requests.ts +443 -0
- package/database/runtimeServerContext.ts +54 -0
- package/database/tenantPlacement.ts +57 -0
- package/database/userPreferenceRegister.ts +131 -0
- package/database/utils/ulid.ts +1 -0
- package/dialogAttachmentCleanup.ts +151 -0
- package/dialogCommands.ts +163 -61
- package/dialogInternalCommandEntries.ts +1 -1
- package/docCreateCommands.ts +345 -0
- package/docInternalCommandEntries.ts +11 -0
- package/docPageHelpers.ts +80 -0
- package/docSkillHelpers.ts +67 -0
- package/docSpaceHelpers.ts +46 -0
- package/integrations/anthropic/anthropicModels.ts +47 -0
- package/integrations/deepseek/models.ts +37 -0
- package/integrations/google/models.ts +341 -0
- package/integrations/openai/chatCompletionStreamMode.ts +10 -0
- package/integrations/openai/filterAndCleanMessages.ts +284 -0
- package/integrations/openai/flexTier.ts +102 -0
- package/integrations/openai/generateOpenAIRequestBody.ts +271 -0
- package/integrations/openai/generateResponseRequestBody.ts +77 -0
- package/integrations/openai/models.ts +271 -0
- package/integrations/openai/providerBodyCompatibility.ts +23 -0
- package/integrations/openai/responsesHelpers.ts +297 -0
- package/integrations/x-reader/types.ts +109 -0
- package/integrations/xai/models.ts +13 -0
- package/integrations/xhs-reader/redaction.ts +68 -0
- package/integrations/xhs-reader/types.ts +277 -0
- package/integrations/xhs-reader/url.ts +80 -0
- package/internalCommandEntries.ts +4 -0
- package/machineCommands.ts +18 -34
- package/memoryCommands.ts +253 -0
- package/memoryInternalCommandEntries.ts +9 -0
- package/package.json +454 -9
- package/qoderUsageProbe.ts +252 -0
- package/render/contentIcon/types.ts +167 -0
- package/render/page/createPageAction.ts +183 -0
- package/render/page/docSlice.ts +495 -0
- package/render/page/types.ts +19 -0
- package/render/table/createTableAction.ts +274 -0
- package/render/table/deleteTableAction.ts +193 -0
- package/render/table/fetchAndCacheTableRows.ts +174 -0
- package/render/table/tableSlice.ts +1167 -0
- package/render/table/toolValueUtils.ts +363 -0
- package/render/table/types.ts +262 -0
- package/render/table/utils/tableSerialization.ts +50 -0
- package/scriptCommandEntries.ts +0 -3
- package/secretScan.ts +31 -0
- package/server/handlers/agentRun/types.ts +105 -0
- package/share/action.ts +225 -0
- package/share/helpers.ts +302 -0
- package/share/keys.ts +243 -0
- package/share/publicSharePolicy.ts +27 -0
- package/share/shareSlice.ts +53 -0
- package/share/types.ts +100 -0
- package/tableCommands.ts +248 -13
- package/workflowInternalCommandEntries.ts +2 -3
- package/ai/tools/agent/taskRunTool.ts +0 -112
- package/cli/client/taskRunPrompt.ts +0 -27
- package/cli/taskRunCommand.ts +0 -265
- package/client/taskRunPrompt.ts +0 -27
- package/taskRunCommand.ts +0 -265
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import type { AgentCommandDeps } from "./agentCommandSupport";
|
|
2
|
+
import {
|
|
3
|
+
readOption,
|
|
4
|
+
resolveAuthToken,
|
|
5
|
+
resolveServerCandidates,
|
|
6
|
+
resolveServerUrl,
|
|
7
|
+
} from "./cliEnvHelpers";
|
|
8
|
+
|
|
9
|
+
const VALUE_FLAGS = new Set([
|
|
10
|
+
"--facet",
|
|
11
|
+
"--id",
|
|
12
|
+
"--ids",
|
|
13
|
+
"--kind",
|
|
14
|
+
"--limit",
|
|
15
|
+
"--pattern-prefix",
|
|
16
|
+
"--server",
|
|
17
|
+
"--server-url",
|
|
18
|
+
"--source-dialog",
|
|
19
|
+
"--subject",
|
|
20
|
+
"--subject-id",
|
|
21
|
+
"--subject-type",
|
|
22
|
+
"--tag",
|
|
23
|
+
"--token",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
function hasFlag(args: string[], flag: string) {
|
|
27
|
+
return args.includes(flag);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function printMemoryDeleteUsage(output: { write(chunk: string): unknown }) {
|
|
31
|
+
output.write(`Usage:
|
|
32
|
+
nolo memory delete --source-dialog <dialogId> --yes [--json]
|
|
33
|
+
nolo memory delete --tag <tag> --kind <kind> --yes
|
|
34
|
+
nolo memory delete --pattern-prefix <prefix> --limit <n> --yes
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--id <memoryId> Delete a specific memory id. Repeatable.
|
|
38
|
+
--ids <a,b,c> Delete specific memory ids.
|
|
39
|
+
--source-dialog <dialogId> Delete memories created from one dialog.
|
|
40
|
+
--tag <tag> Require a tag. Repeatable.
|
|
41
|
+
--kind <kind> Filter episodic / semantic / procedural. Repeatable.
|
|
42
|
+
--facet <facet> Filter preference / tension / unfinished / goal / style. Repeatable.
|
|
43
|
+
--subject-type <type> Filter user / agent / space / project / system.
|
|
44
|
+
--subject <subjectId> Filter subjectId.
|
|
45
|
+
--pattern-prefix <prefix> Filter patternKey prefix.
|
|
46
|
+
--limit <n> Maximum memories to delete.
|
|
47
|
+
--yes Actually delete. Without this, command is a dry-run.
|
|
48
|
+
--json Print machine-readable JSON.
|
|
49
|
+
--server <url> Prefer this server and include known Nolo peers.
|
|
50
|
+
--token <jwt> Override AUTH_TOKEN.
|
|
51
|
+
|
|
52
|
+
At least one filter is required; this command will not delete all memory implicitly.
|
|
53
|
+
`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function readRepeated(args: string[], flag: string) {
|
|
57
|
+
const values: string[] = [];
|
|
58
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
59
|
+
if (args[index] !== flag) continue;
|
|
60
|
+
const value = args[index + 1];
|
|
61
|
+
if (typeof value === "string" && value.trim()) values.push(value.trim());
|
|
62
|
+
}
|
|
63
|
+
return values;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function readCsvValues(args: string[], flag: string) {
|
|
67
|
+
const raw = readRepeated(args, flag).join(",");
|
|
68
|
+
return raw
|
|
69
|
+
.split(",")
|
|
70
|
+
.map((value) => value.trim())
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function readLimit(args: string[]) {
|
|
75
|
+
const raw = readOption(args, "--limit");
|
|
76
|
+
if (!raw) return undefined;
|
|
77
|
+
if (!/^\d+$/.test(raw)) throw new Error(`invalid --limit: ${raw}`);
|
|
78
|
+
const parsed = Number(raw);
|
|
79
|
+
return parsed > 0 ? parsed : undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function assertNoUnknownFlags(args: string[]) {
|
|
83
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
84
|
+
const value = args[index];
|
|
85
|
+
if (!value.startsWith("-")) continue;
|
|
86
|
+
if (value === "--help" || value === "-h" || value === "--yes" || value === "--json") continue;
|
|
87
|
+
if (VALUE_FLAGS.has(value)) {
|
|
88
|
+
index += 1;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`unknown option: ${value}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildDeleteBody(args: string[]) {
|
|
96
|
+
const ids = [...readRepeated(args, "--id"), ...readCsvValues(args, "--ids")];
|
|
97
|
+
const kinds = readRepeated(args, "--kind");
|
|
98
|
+
const facets = readRepeated(args, "--facet");
|
|
99
|
+
const tags = readRepeated(args, "--tag");
|
|
100
|
+
const sourceDialogId = readOption(args, "--source-dialog")?.trim();
|
|
101
|
+
const subjectType = readOption(args, "--subject-type")?.trim();
|
|
102
|
+
const subjectId = (readOption(args, "--subject") ?? readOption(args, "--subject-id"))?.trim();
|
|
103
|
+
const patternKeyPrefix = readOption(args, "--pattern-prefix")?.trim();
|
|
104
|
+
const limit = readLimit(args);
|
|
105
|
+
|
|
106
|
+
const body: Record<string, unknown> = {};
|
|
107
|
+
if (ids.length) body.ids = [...new Set(ids)];
|
|
108
|
+
if (kinds.length) body.kinds = [...new Set(kinds)];
|
|
109
|
+
if (facets.length) body.facets = [...new Set(facets)];
|
|
110
|
+
if (tags.length) body.tags = [...new Set(tags)];
|
|
111
|
+
if (sourceDialogId) body.sourceDialogId = sourceDialogId;
|
|
112
|
+
if (subjectType) body.subjectType = subjectType;
|
|
113
|
+
if (subjectId) body.subjectId = subjectId;
|
|
114
|
+
if (patternKeyPrefix) body.patternKeyPrefix = patternKeyPrefix;
|
|
115
|
+
if (typeof limit === "number") body.limit = limit;
|
|
116
|
+
return body;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function hasDeleteFilter(body: Record<string, unknown>) {
|
|
120
|
+
return Object.keys(body).some((key) => key !== "limit");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function postMemoryDelete(args: {
|
|
124
|
+
authToken: string;
|
|
125
|
+
body: Record<string, unknown>;
|
|
126
|
+
fetchImpl: typeof fetch;
|
|
127
|
+
serverUrl: string;
|
|
128
|
+
}) {
|
|
129
|
+
const res = await args.fetchImpl(`${args.serverUrl}/api/memory/delete`, {
|
|
130
|
+
method: "POST",
|
|
131
|
+
headers: {
|
|
132
|
+
Authorization: `Bearer ${args.authToken}`,
|
|
133
|
+
"Content-Type": "application/json",
|
|
134
|
+
},
|
|
135
|
+
body: JSON.stringify(args.body),
|
|
136
|
+
});
|
|
137
|
+
const text = await res.text();
|
|
138
|
+
let payload: any = null;
|
|
139
|
+
try {
|
|
140
|
+
payload = text ? JSON.parse(text) : null;
|
|
141
|
+
} catch {
|
|
142
|
+
payload = { raw: text };
|
|
143
|
+
}
|
|
144
|
+
if (!res.ok || payload?.error) {
|
|
145
|
+
const message =
|
|
146
|
+
payload?.error?.message ??
|
|
147
|
+
payload?.message ??
|
|
148
|
+
payload?.error ??
|
|
149
|
+
`HTTP ${res.status}`;
|
|
150
|
+
throw new Error(`${message}`);
|
|
151
|
+
}
|
|
152
|
+
return payload;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function runMemoryDeleteCommand(
|
|
156
|
+
args: string[],
|
|
157
|
+
deps: AgentCommandDeps = {}
|
|
158
|
+
) {
|
|
159
|
+
const env = deps.env ?? process.env;
|
|
160
|
+
const output = deps.output ?? process.stdout;
|
|
161
|
+
if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
|
|
162
|
+
printMemoryDeleteUsage(output);
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
assertNoUnknownFlags(args);
|
|
168
|
+
const authToken = resolveAuthToken(args, env);
|
|
169
|
+
if (!authToken) {
|
|
170
|
+
output.write("[nolo] memory delete requires an auth token. Run `nolo login` or set AUTH_TOKEN.\n");
|
|
171
|
+
return 1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const body = buildDeleteBody(args);
|
|
175
|
+
if (!hasDeleteFilter(body)) {
|
|
176
|
+
output.write("[nolo] memory delete requires at least one filter; use --help for examples.\n");
|
|
177
|
+
return 1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const shouldDelete = hasFlag(args, "--yes");
|
|
181
|
+
const wantJson = hasFlag(args, "--json");
|
|
182
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
183
|
+
const serverUrl = resolveServerUrl(args, env);
|
|
184
|
+
const serverUrls = resolveServerCandidates(args, env, serverUrl);
|
|
185
|
+
|
|
186
|
+
if (!shouldDelete) {
|
|
187
|
+
const payload = {
|
|
188
|
+
dryRun: true,
|
|
189
|
+
deleted: false,
|
|
190
|
+
targetServers: serverUrls,
|
|
191
|
+
request: body,
|
|
192
|
+
nextStep: "rerun with --yes to delete matching memories",
|
|
193
|
+
};
|
|
194
|
+
if (wantJson) {
|
|
195
|
+
output.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
196
|
+
} else {
|
|
197
|
+
output.write("dryRun: true\n");
|
|
198
|
+
output.write(`targetServers: ${serverUrls.join(", ")}\n`);
|
|
199
|
+
output.write(`request: ${JSON.stringify(body)}\n`);
|
|
200
|
+
output.write("rerun with --yes to delete matching memories\n");
|
|
201
|
+
}
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const deleteResults = [];
|
|
206
|
+
for (const target of serverUrls) {
|
|
207
|
+
try {
|
|
208
|
+
const result = await postMemoryDelete({
|
|
209
|
+
authToken,
|
|
210
|
+
body,
|
|
211
|
+
fetchImpl,
|
|
212
|
+
serverUrl: target,
|
|
213
|
+
});
|
|
214
|
+
deleteResults.push({ serverUrl: target, ok: true, result });
|
|
215
|
+
} catch (error) {
|
|
216
|
+
deleteResults.push({
|
|
217
|
+
serverUrl: target,
|
|
218
|
+
ok: false,
|
|
219
|
+
error: error instanceof Error ? error.message : String(error),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const deletedCount = deleteResults.reduce(
|
|
225
|
+
(sum, item) => sum + (item.ok ? Number(item.result?.deletedCount ?? 0) : 0),
|
|
226
|
+
0
|
|
227
|
+
);
|
|
228
|
+
const payload = {
|
|
229
|
+
dryRun: false,
|
|
230
|
+
deleted: true,
|
|
231
|
+
deletedCount,
|
|
232
|
+
request: body,
|
|
233
|
+
targetServers: serverUrls,
|
|
234
|
+
deleteResults,
|
|
235
|
+
};
|
|
236
|
+
if (wantJson) {
|
|
237
|
+
output.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
238
|
+
} else {
|
|
239
|
+
output.write(`deletedCount: ${deletedCount}\n`);
|
|
240
|
+
for (const result of deleteResults) {
|
|
241
|
+
output.write(
|
|
242
|
+
result.ok
|
|
243
|
+
? `${result.serverUrl}: ok deleted=${result.result?.deletedCount ?? 0}\n`
|
|
244
|
+
: `${result.serverUrl}: failed ${result.error}\n`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return deleteResults.some((result) => result.ok) ? 0 : 1;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
output.write(`[nolo] memory delete failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
251
|
+
return 1;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CommandEntry } from "./cliCommandTypes";
|
|
2
|
+
import { createEnvCommand } from "./cliCommandFactories";
|
|
3
|
+
import { runMemoryDeleteCommand } from "./memoryCommands";
|
|
4
|
+
|
|
5
|
+
export function getMemoryInternalCommandEntries(): CommandEntry[] {
|
|
6
|
+
return [
|
|
7
|
+
createEnvCommand(["memory", "delete"], "Delete long-term memories by filter", runMemoryDeleteCommand),
|
|
8
|
+
];
|
|
9
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -2,15 +2,12 @@ import { createScriptCommand, type CommandEntry } from "./cliCommandTypes";
|
|
|
2
2
|
|
|
3
3
|
function getDocScriptCommands(): CommandEntry[] {
|
|
4
4
|
return [
|
|
5
|
-
createScriptCommand(["doc", "create"], "createDoc.ts", "Create a normal doc"),
|
|
6
5
|
createScriptCommand(["doc", "read"], "readDoc.ts", "Read a normal doc"),
|
|
7
6
|
createScriptCommand(["doc", "update"], "updateDoc.ts", "Update a normal doc"),
|
|
8
7
|
createScriptCommand(["doc", "delete"], "deleteDoc.ts", "Delete a normal doc"),
|
|
9
|
-
createScriptCommand(["skill-doc", "create"], "createSkillDoc.ts", "Create a skill doc"),
|
|
10
8
|
createScriptCommand(["skill-doc", "read"], "readSkillDoc.ts", "Read a skill doc"),
|
|
11
9
|
createScriptCommand(["skill-doc", "update"], "updateSkillDoc.ts", "Update a skill doc"),
|
|
12
10
|
createScriptCommand(["skill-doc", "delete"], "deleteSkillDoc.ts", "Delete a skill doc"),
|
|
13
|
-
createScriptCommand(["skill", "create-doc"], "createSkillDoc.ts", "Create a skill-backed doc"),
|
|
14
11
|
];
|
|
15
12
|
}
|
|
16
13
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type SecretFinding = {
|
|
2
|
+
label: string;
|
|
3
|
+
line: number;
|
|
4
|
+
preview: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const SECRET_PATTERNS: Array<{ label: string; pattern: RegExp }> = [
|
|
8
|
+
{ label: "password", pattern: /\bpassword\s*[:=]\s*["']?[^"',\s#]{8,}/i },
|
|
9
|
+
{ label: "psk", pattern: /\bpsk\s*[:=]\s*["']?[^"',\s#]{8,}/i },
|
|
10
|
+
{ label: "api key", pattern: /\b(api[_-]?key|apikey)\s*[:=]\s*["']?[^"',\s#]{12,}/i },
|
|
11
|
+
{ label: "token", pattern: /\b(token|secret)\s*[:=]\s*["']?[^"',\s#]{12,}/i },
|
|
12
|
+
{ label: "private key", pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export function findPotentialSecrets(text: string): SecretFinding[] {
|
|
16
|
+
return text
|
|
17
|
+
.split(/\r?\n/)
|
|
18
|
+
.flatMap((line, index) =>
|
|
19
|
+
SECRET_PATTERNS.filter(({ pattern }) => pattern.test(line)).map(({ label }) => ({
|
|
20
|
+
label,
|
|
21
|
+
line: index + 1,
|
|
22
|
+
preview: line.length > 120 ? `${line.slice(0, 117)}...` : line,
|
|
23
|
+
}))
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function formatSecretFindings(findings: SecretFinding[]) {
|
|
28
|
+
return findings
|
|
29
|
+
.map((finding) => ` line ${finding.line} (${finding.label}): ${finding.preview}`)
|
|
30
|
+
.join("\n");
|
|
31
|
+
}
|