@vybestack/llxprt-code-core 0.1.12
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/dist/.last_build +0 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/src/__mocks__/fs/promises.d.ts +11 -0
- package/dist/src/__mocks__/fs/promises.js +17 -0
- package/dist/src/__mocks__/fs/promises.js.map +1 -0
- package/dist/src/code_assist/codeAssist.d.ts +9 -0
- package/dist/src/code_assist/codeAssist.js +19 -0
- package/dist/src/code_assist/codeAssist.js.map +1 -0
- package/dist/src/code_assist/converter.d.ts +68 -0
- package/dist/src/code_assist/converter.js +125 -0
- package/dist/src/code_assist/converter.js.map +1 -0
- package/dist/src/code_assist/converter.test.d.ts +6 -0
- package/dist/src/code_assist/converter.test.js +229 -0
- package/dist/src/code_assist/converter.test.js.map +1 -0
- package/dist/src/code_assist/oauth2.d.ts +20 -0
- package/dist/src/code_assist/oauth2.js +339 -0
- package/dist/src/code_assist/oauth2.js.map +1 -0
- package/dist/src/code_assist/oauth2.test.d.ts +6 -0
- package/dist/src/code_assist/oauth2.test.js +249 -0
- package/dist/src/code_assist/oauth2.test.js.map +1 -0
- package/dist/src/code_assist/server.d.ts +39 -0
- package/dist/src/code_assist/server.js +191 -0
- package/dist/src/code_assist/server.js.map +1 -0
- package/dist/src/code_assist/server.test.d.ts +6 -0
- package/dist/src/code_assist/server.test.js +123 -0
- package/dist/src/code_assist/server.test.js.map +1 -0
- package/dist/src/code_assist/setup.d.ts +15 -0
- package/dist/src/code_assist/setup.js +67 -0
- package/dist/src/code_assist/setup.js.map +1 -0
- package/dist/src/code_assist/setup.test.d.ts +6 -0
- package/dist/src/code_assist/setup.test.js +62 -0
- package/dist/src/code_assist/setup.test.js.map +1 -0
- package/dist/src/code_assist/types.d.ts +148 -0
- package/dist/src/code_assist/types.js +46 -0
- package/dist/src/code_assist/types.js.map +1 -0
- package/dist/src/config/config.d.ts +212 -0
- package/dist/src/config/config.js +454 -0
- package/dist/src/config/config.js.map +1 -0
- package/dist/src/config/config.test.d.ts +6 -0
- package/dist/src/config/config.test.js +291 -0
- package/dist/src/config/config.test.js.map +1 -0
- package/dist/src/config/flashFallback.test.d.ts +6 -0
- package/dist/src/config/flashFallback.test.js +115 -0
- package/dist/src/config/flashFallback.test.js.map +1 -0
- package/dist/src/config/models.d.ts +8 -0
- package/dist/src/config/models.js +9 -0
- package/dist/src/config/models.js.map +1 -0
- package/dist/src/core/client.d.ts +59 -0
- package/dist/src/core/client.js +503 -0
- package/dist/src/core/client.js.map +1 -0
- package/dist/src/core/client.test.d.ts +6 -0
- package/dist/src/core/client.test.js +1006 -0
- package/dist/src/core/client.test.js.map +1 -0
- package/dist/src/core/contentGenerator.d.ts +36 -0
- package/dist/src/core/contentGenerator.js +79 -0
- package/dist/src/core/contentGenerator.js.map +1 -0
- package/dist/src/core/contentGenerator.test.d.ts +6 -0
- package/dist/src/core/contentGenerator.test.js +92 -0
- package/dist/src/core/contentGenerator.test.js.map +1 -0
- package/dist/src/core/coreToolScheduler.d.ts +104 -0
- package/dist/src/core/coreToolScheduler.js +413 -0
- package/dist/src/core/coreToolScheduler.js.map +1 -0
- package/dist/src/core/coreToolScheduler.test.d.ts +6 -0
- package/dist/src/core/coreToolScheduler.test.js +347 -0
- package/dist/src/core/coreToolScheduler.test.js.map +1 -0
- package/dist/src/core/geminiChat.d.ts +116 -0
- package/dist/src/core/geminiChat.js +513 -0
- package/dist/src/core/geminiChat.js.map +1 -0
- package/dist/src/core/geminiChat.test.d.ts +6 -0
- package/dist/src/core/geminiChat.test.js +424 -0
- package/dist/src/core/geminiChat.test.js.map +1 -0
- package/dist/src/core/geminiRequest.d.ts +13 -0
- package/dist/src/core/geminiRequest.js +45 -0
- package/dist/src/core/geminiRequest.js.map +1 -0
- package/dist/src/core/geminiRequest.test.d.ts +6 -0
- package/dist/src/core/geminiRequest.test.js +72 -0
- package/dist/src/core/geminiRequest.test.js.map +1 -0
- package/dist/src/core/logger.d.ts +38 -0
- package/dist/src/core/logger.js +237 -0
- package/dist/src/core/logger.js.map +1 -0
- package/dist/src/core/logger.test.d.ts +6 -0
- package/dist/src/core/logger.test.js +387 -0
- package/dist/src/core/logger.test.js.map +1 -0
- package/dist/src/core/modelCheck.d.ts +14 -0
- package/dist/src/core/modelCheck.js +55 -0
- package/dist/src/core/modelCheck.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.d.ts +12 -0
- package/dist/src/core/nonInteractiveToolExecutor.js +93 -0
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.test.d.ts +6 -0
- package/dist/src/core/nonInteractiveToolExecutor.test.js +180 -0
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -0
- package/dist/src/core/prompts.d.ts +12 -0
- package/dist/src/core/prompts.js +418 -0
- package/dist/src/core/prompts.js.map +1 -0
- package/dist/src/core/prompts.test.d.ts +6 -0
- package/dist/src/core/prompts.test.js +97 -0
- package/dist/src/core/prompts.test.js.map +1 -0
- package/dist/src/core/tokenLimits.d.ts +10 -0
- package/dist/src/core/tokenLimits.js +75 -0
- package/dist/src/core/tokenLimits.js.map +1 -0
- package/dist/src/core/tokenLimits.test.d.ts +6 -0
- package/dist/src/core/tokenLimits.test.js +66 -0
- package/dist/src/core/tokenLimits.test.js.map +1 -0
- package/dist/src/core/turn.d.ts +116 -0
- package/dist/src/core/turn.js +131 -0
- package/dist/src/core/turn.js.map +1 -0
- package/dist/src/core/turn.test.d.ts +6 -0
- package/dist/src/core/turn.test.js +237 -0
- package/dist/src/core/turn.test.js.map +1 -0
- package/dist/src/index.d.ts +57 -0
- package/dist/src/index.js +64 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/index.test.d.ts +6 -0
- package/dist/src/index.test.js +12 -0
- package/dist/src/index.test.js.map +1 -0
- package/dist/src/providers/ProviderContentGenerator.d.ts +21 -0
- package/dist/src/providers/ProviderContentGenerator.js +52 -0
- package/dist/src/providers/ProviderContentGenerator.js.map +1 -0
- package/dist/src/providers/adapters/GeminiCompatibleWrapper.d.ts +68 -0
- package/dist/src/providers/adapters/GeminiCompatibleWrapper.js +549 -0
- package/dist/src/providers/adapters/GeminiCompatibleWrapper.js.map +1 -0
- package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.d.ts +6 -0
- package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js +253 -0
- package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js.map +1 -0
- package/dist/src/providers/types.d.ts +82 -0
- package/dist/src/providers/types.js +7 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.d.ts +35 -0
- package/dist/src/services/fileDiscoveryService.js +91 -0
- package/dist/src/services/fileDiscoveryService.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.test.d.ts +6 -0
- package/dist/src/services/fileDiscoveryService.test.js +102 -0
- package/dist/src/services/fileDiscoveryService.test.js.map +1 -0
- package/dist/src/services/gitService.d.ts +21 -0
- package/dist/src/services/gitService.js +102 -0
- package/dist/src/services/gitService.js.map +1 -0
- package/dist/src/services/gitService.test.d.ts +6 -0
- package/dist/src/services/gitService.test.js +246 -0
- package/dist/src/services/gitService.test.js.map +1 -0
- package/dist/src/services/ideContext.d.ts +124 -0
- package/dist/src/services/ideContext.js +90 -0
- package/dist/src/services/ideContext.js.map +1 -0
- package/dist/src/services/ideContext.test.d.ts +6 -0
- package/dist/src/services/ideContext.test.js +101 -0
- package/dist/src/services/ideContext.test.js.map +1 -0
- package/dist/src/services/loopDetectionService.d.ts +35 -0
- package/dist/src/services/loopDetectionService.js +117 -0
- package/dist/src/services/loopDetectionService.js.map +1 -0
- package/dist/src/services/loopDetectionService.test.d.ts +6 -0
- package/dist/src/services/loopDetectionService.test.js +232 -0
- package/dist/src/services/loopDetectionService.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +35 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +424 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +47 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +123 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -0
- package/dist/src/telemetry/constants.d.ts +20 -0
- package/dist/src/telemetry/constants.js +21 -0
- package/dist/src/telemetry/constants.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +18 -0
- package/dist/src/telemetry/index.js +20 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/integration.test.circular.d.ts +6 -0
- package/dist/src/telemetry/integration.test.circular.js +53 -0
- package/dist/src/telemetry/integration.test.circular.js.map +1 -0
- package/dist/src/telemetry/loggers.d.ts +15 -0
- package/dist/src/telemetry/loggers.js +229 -0
- package/dist/src/telemetry/loggers.js.map +1 -0
- package/dist/src/telemetry/loggers.test.circular.d.ts +6 -0
- package/dist/src/telemetry/loggers.test.circular.js +100 -0
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -0
- package/dist/src/telemetry/loggers.test.d.ts +6 -0
- package/dist/src/telemetry/loggers.test.js +558 -0
- package/dist/src/telemetry/loggers.test.js.map +1 -0
- package/dist/src/telemetry/metrics.d.ts +19 -0
- package/dist/src/telemetry/metrics.js +144 -0
- package/dist/src/telemetry/metrics.js.map +1 -0
- package/dist/src/telemetry/metrics.test.d.ts +6 -0
- package/dist/src/telemetry/metrics.test.js +162 -0
- package/dist/src/telemetry/metrics.test.js.map +1 -0
- package/dist/src/telemetry/sdk.d.ts +9 -0
- package/dist/src/telemetry/sdk.js +120 -0
- package/dist/src/telemetry/sdk.js.map +1 -0
- package/dist/src/telemetry/telemetry.test.d.ts +6 -0
- package/dist/src/telemetry/telemetry.test.js +52 -0
- package/dist/src/telemetry/telemetry.test.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +115 -0
- package/dist/src/telemetry/types.js +217 -0
- package/dist/src/telemetry/types.js.map +1 -0
- package/dist/src/telemetry/uiTelemetry.d.ts +67 -0
- package/dist/src/telemetry/uiTelemetry.js +131 -0
- package/dist/src/telemetry/uiTelemetry.js.map +1 -0
- package/dist/src/telemetry/uiTelemetry.test.d.ts +6 -0
- package/dist/src/telemetry/uiTelemetry.test.js +412 -0
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -0
- package/dist/src/tools/diffOptions.d.ts +7 -0
- package/dist/src/tools/diffOptions.js +10 -0
- package/dist/src/tools/diffOptions.js.map +1 -0
- package/dist/src/tools/edit.d.ts +73 -0
- package/dist/src/tools/edit.js +343 -0
- package/dist/src/tools/edit.js.map +1 -0
- package/dist/src/tools/edit.test.d.ts +6 -0
- package/dist/src/tools/edit.test.js +500 -0
- package/dist/src/tools/edit.test.js.map +1 -0
- package/dist/src/tools/glob.d.ts +58 -0
- package/dist/src/tools/glob.js +193 -0
- package/dist/src/tools/glob.js.map +1 -0
- package/dist/src/tools/glob.test.d.ts +6 -0
- package/dist/src/tools/glob.test.js +294 -0
- package/dist/src/tools/glob.test.js.map +1 -0
- package/dist/src/tools/grep.d.ts +78 -0
- package/dist/src/tools/grep.js +422 -0
- package/dist/src/tools/grep.js.map +1 -0
- package/dist/src/tools/grep.test.d.ts +6 -0
- package/dist/src/tools/grep.test.js +188 -0
- package/dist/src/tools/grep.test.js.map +1 -0
- package/dist/src/tools/ls.d.ts +83 -0
- package/dist/src/tools/ls.js +194 -0
- package/dist/src/tools/ls.js.map +1 -0
- package/dist/src/tools/mcp-client.d.ts +112 -0
- package/dist/src/tools/mcp-client.js +332 -0
- package/dist/src/tools/mcp-client.js.map +1 -0
- package/dist/src/tools/mcp-client.test.d.ts +6 -0
- package/dist/src/tools/mcp-client.test.js +227 -0
- package/dist/src/tools/mcp-client.test.js.map +1 -0
- package/dist/src/tools/mcp-tool.d.ts +23 -0
- package/dist/src/tools/mcp-tool.js +119 -0
- package/dist/src/tools/mcp-tool.js.map +1 -0
- package/dist/src/tools/mcp-tool.test.d.ts +6 -0
- package/dist/src/tools/mcp-tool.test.js +173 -0
- package/dist/src/tools/mcp-tool.test.js.map +1 -0
- package/dist/src/tools/memoryTool.d.ts +28 -0
- package/dist/src/tools/memoryTool.js +172 -0
- package/dist/src/tools/memoryTool.js.map +1 -0
- package/dist/src/tools/memoryTool.test.d.ts +6 -0
- package/dist/src/tools/memoryTool.test.js +181 -0
- package/dist/src/tools/memoryTool.test.js.map +1 -0
- package/dist/src/tools/modifiable-tool.d.ts +29 -0
- package/dist/src/tools/modifiable-tool.js +85 -0
- package/dist/src/tools/modifiable-tool.js.map +1 -0
- package/dist/src/tools/modifiable-tool.test.d.ts +6 -0
- package/dist/src/tools/modifiable-tool.test.js +204 -0
- package/dist/src/tools/modifiable-tool.test.js.map +1 -0
- package/dist/src/tools/read-file.d.ts +35 -0
- package/dist/src/tools/read-file.js +106 -0
- package/dist/src/tools/read-file.js.map +1 -0
- package/dist/src/tools/read-file.test.d.ts +6 -0
- package/dist/src/tools/read-file.test.js +181 -0
- package/dist/src/tools/read-file.test.js.map +1 -0
- package/dist/src/tools/read-many-files.d.ts +59 -0
- package/dist/src/tools/read-many-files.js +321 -0
- package/dist/src/tools/read-many-files.js.map +1 -0
- package/dist/src/tools/read-many-files.test.d.ts +6 -0
- package/dist/src/tools/read-many-files.test.js +312 -0
- package/dist/src/tools/read-many-files.test.js.map +1 -0
- package/dist/src/tools/shell.d.ts +43 -0
- package/dist/src/tools/shell.js +435 -0
- package/dist/src/tools/shell.js.map +1 -0
- package/dist/src/tools/shell.test.d.ts +6 -0
- package/dist/src/tools/shell.test.js +407 -0
- package/dist/src/tools/shell.test.js.map +1 -0
- package/dist/src/tools/todo-read.d.ts +15 -0
- package/dist/src/tools/todo-read.js +66 -0
- package/dist/src/tools/todo-read.js.map +1 -0
- package/dist/src/tools/todo-read.test.d.ts +6 -0
- package/dist/src/tools/todo-read.test.js +158 -0
- package/dist/src/tools/todo-read.test.js.map +1 -0
- package/dist/src/tools/todo-schemas.d.ts +43 -0
- package/dist/src/tools/todo-schemas.js +16 -0
- package/dist/src/tools/todo-schemas.js.map +1 -0
- package/dist/src/tools/todo-schemas.test.d.ts +6 -0
- package/dist/src/tools/todo-schemas.test.js +152 -0
- package/dist/src/tools/todo-schemas.test.js.map +1 -0
- package/dist/src/tools/todo-store.d.ts +15 -0
- package/dist/src/tools/todo-store.js +59 -0
- package/dist/src/tools/todo-store.js.map +1 -0
- package/dist/src/tools/todo-store.test.d.ts +6 -0
- package/dist/src/tools/todo-store.test.js +175 -0
- package/dist/src/tools/todo-store.test.js.map +1 -0
- package/dist/src/tools/todo-write.d.ts +17 -0
- package/dist/src/tools/todo-write.js +98 -0
- package/dist/src/tools/todo-write.js.map +1 -0
- package/dist/src/tools/todo-write.test.d.ts +6 -0
- package/dist/src/tools/todo-write.test.js +208 -0
- package/dist/src/tools/todo-write.test.js.map +1 -0
- package/dist/src/tools/tool-registry.d.ts +67 -0
- package/dist/src/tools/tool-registry.js +326 -0
- package/dist/src/tools/tool-registry.js.map +1 -0
- package/dist/src/tools/tool-registry.test.d.ts +6 -0
- package/dist/src/tools/tool-registry.test.js +398 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -0
- package/dist/src/tools/tools.d.ts +184 -0
- package/dist/src/tools/tools.js +88 -0
- package/dist/src/tools/tools.js.map +1 -0
- package/dist/src/tools/web-fetch.d.ts +29 -0
- package/dist/src/tools/web-fetch.js +243 -0
- package/dist/src/tools/web-fetch.js.map +1 -0
- package/dist/src/tools/web-fetch.test.d.ts +6 -0
- package/dist/src/tools/web-fetch.test.js +70 -0
- package/dist/src/tools/web-fetch.test.js.map +1 -0
- package/dist/src/tools/web-search.d.ts +49 -0
- package/dist/src/tools/web-search.js +120 -0
- package/dist/src/tools/web-search.js.map +1 -0
- package/dist/src/tools/write-file.d.ts +42 -0
- package/dist/src/tools/write-file.js +248 -0
- package/dist/src/tools/write-file.js.map +1 -0
- package/dist/src/tools/write-file.test.d.ts +6 -0
- package/dist/src/tools/write-file.test.js +413 -0
- package/dist/src/tools/write-file.test.js.map +1 -0
- package/dist/src/utils/LruCache.d.ts +13 -0
- package/dist/src/utils/LruCache.js +38 -0
- package/dist/src/utils/LruCache.js.map +1 -0
- package/dist/src/utils/bfsFileSearch.d.ts +22 -0
- package/dist/src/utils/bfsFileSearch.js +62 -0
- package/dist/src/utils/bfsFileSearch.js.map +1 -0
- package/dist/src/utils/bfsFileSearch.test.d.ts +6 -0
- package/dist/src/utils/bfsFileSearch.test.js +129 -0
- package/dist/src/utils/bfsFileSearch.test.js.map +1 -0
- package/dist/src/utils/editCorrector.d.ts +53 -0
- package/dist/src/utils/editCorrector.js +546 -0
- package/dist/src/utils/editCorrector.js.map +1 -0
- package/dist/src/utils/editCorrector.test.d.ts +6 -0
- package/dist/src/utils/editCorrector.test.js +564 -0
- package/dist/src/utils/editCorrector.test.js.map +1 -0
- package/dist/src/utils/editor.d.ts +28 -0
- package/dist/src/utils/editor.js +163 -0
- package/dist/src/utils/editor.js.map +1 -0
- package/dist/src/utils/editor.test.d.ts +6 -0
- package/dist/src/utils/editor.test.js +293 -0
- package/dist/src/utils/editor.test.js.map +1 -0
- package/dist/src/utils/errorReporting.d.ts +14 -0
- package/dist/src/utils/errorReporting.js +88 -0
- package/dist/src/utils/errorReporting.js.map +1 -0
- package/dist/src/utils/errorReporting.test.d.ts +6 -0
- package/dist/src/utils/errorReporting.test.js +124 -0
- package/dist/src/utils/errorReporting.test.js.map +1 -0
- package/dist/src/utils/errors.d.ts +14 -0
- package/dist/src/utils/errors.js +54 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/fetch.d.ts +11 -0
- package/dist/src/utils/fetch.js +51 -0
- package/dist/src/utils/fetch.js.map +1 -0
- package/dist/src/utils/fileUtils.d.ts +49 -0
- package/dist/src/utils/fileUtils.js +286 -0
- package/dist/src/utils/fileUtils.js.map +1 -0
- package/dist/src/utils/fileUtils.test.d.ts +6 -0
- package/dist/src/utils/fileUtils.test.js +321 -0
- package/dist/src/utils/fileUtils.test.js.map +1 -0
- package/dist/src/utils/flashFallback.integration.test.d.ts +6 -0
- package/dist/src/utils/flashFallback.integration.test.js +112 -0
- package/dist/src/utils/flashFallback.integration.test.js.map +1 -0
- package/dist/src/utils/generateContentResponseUtilities.d.ts +14 -0
- package/dist/src/utils/generateContentResponseUtilities.js +92 -0
- package/dist/src/utils/generateContentResponseUtilities.js.map +1 -0
- package/dist/src/utils/generateContentResponseUtilities.test.d.ts +6 -0
- package/dist/src/utils/generateContentResponseUtilities.test.js +273 -0
- package/dist/src/utils/generateContentResponseUtilities.test.js.map +1 -0
- package/dist/src/utils/getFolderStructure.d.ts +30 -0
- package/dist/src/utils/getFolderStructure.js +247 -0
- package/dist/src/utils/getFolderStructure.js.map +1 -0
- package/dist/src/utils/getFolderStructure.test.d.ts +6 -0
- package/dist/src/utils/getFolderStructure.test.js +298 -0
- package/dist/src/utils/getFolderStructure.test.js.map +1 -0
- package/dist/src/utils/gitIgnoreParser.d.ts +20 -0
- package/dist/src/utils/gitIgnoreParser.js +64 -0
- package/dist/src/utils/gitIgnoreParser.js.map +1 -0
- package/dist/src/utils/gitIgnoreParser.test.d.ts +6 -0
- package/dist/src/utils/gitIgnoreParser.test.js +145 -0
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -0
- package/dist/src/utils/gitUtils.d.ts +17 -0
- package/dist/src/utils/gitUtils.js +61 -0
- package/dist/src/utils/gitUtils.js.map +1 -0
- package/dist/src/utils/memoryDiscovery.d.ts +14 -0
- package/dist/src/utils/memoryDiscovery.js +219 -0
- package/dist/src/utils/memoryDiscovery.js.map +1 -0
- package/dist/src/utils/memoryDiscovery.test.d.ts +6 -0
- package/dist/src/utils/memoryDiscovery.test.js +432 -0
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -0
- package/dist/src/utils/memoryImportProcessor.d.ts +35 -0
- package/dist/src/utils/memoryImportProcessor.js +141 -0
- package/dist/src/utils/memoryImportProcessor.js.map +1 -0
- package/dist/src/utils/memoryImportProcessor.test.d.ts +6 -0
- package/dist/src/utils/memoryImportProcessor.test.js +170 -0
- package/dist/src/utils/memoryImportProcessor.test.js.map +1 -0
- package/dist/src/utils/messageInspectors.d.ts +8 -0
- package/dist/src/utils/messageInspectors.js +16 -0
- package/dist/src/utils/messageInspectors.js.map +1 -0
- package/dist/src/utils/nextSpeakerChecker.d.ts +12 -0
- package/dist/src/utils/nextSpeakerChecker.js +113 -0
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -0
- package/dist/src/utils/nextSpeakerChecker.test.d.ts +6 -0
- package/dist/src/utils/nextSpeakerChecker.test.js +168 -0
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -0
- package/dist/src/utils/paths.d.ts +49 -0
- package/dist/src/utils/paths.js +145 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/dist/src/utils/quotaErrorDetection.d.ts +22 -0
- package/dist/src/utils/quotaErrorDetection.js +67 -0
- package/dist/src/utils/quotaErrorDetection.js.map +1 -0
- package/dist/src/utils/retry.d.ts +21 -0
- package/dist/src/utils/retry.js +276 -0
- package/dist/src/utils/retry.js.map +1 -0
- package/dist/src/utils/retry.test.d.ts +6 -0
- package/dist/src/utils/retry.test.js +322 -0
- package/dist/src/utils/retry.test.js.map +1 -0
- package/dist/src/utils/safeJsonStringify.d.ts +13 -0
- package/dist/src/utils/safeJsonStringify.js +25 -0
- package/dist/src/utils/safeJsonStringify.js.map +1 -0
- package/dist/src/utils/safeJsonStringify.test.d.ts +6 -0
- package/dist/src/utils/safeJsonStringify.test.js +61 -0
- package/dist/src/utils/safeJsonStringify.test.js.map +1 -0
- package/dist/src/utils/schemaValidator.d.ts +23 -0
- package/dist/src/utils/schemaValidator.js +142 -0
- package/dist/src/utils/schemaValidator.js.map +1 -0
- package/dist/src/utils/schemaValidator.test.d.ts +6 -0
- package/dist/src/utils/schemaValidator.test.js +146 -0
- package/dist/src/utils/schemaValidator.test.js.map +1 -0
- package/dist/src/utils/session.d.ts +6 -0
- package/dist/src/utils/session.js +8 -0
- package/dist/src/utils/session.js.map +1 -0
- package/dist/src/utils/summarizer.d.ts +25 -0
- package/dist/src/utils/summarizer.js +80 -0
- package/dist/src/utils/summarizer.js.map +1 -0
- package/dist/src/utils/summarizer.test.d.ts +6 -0
- package/dist/src/utils/summarizer.test.js +131 -0
- package/dist/src/utils/summarizer.test.js.map +1 -0
- package/dist/src/utils/testUtils.d.ts +29 -0
- package/dist/src/utils/testUtils.js +70 -0
- package/dist/src/utils/testUtils.js.map +1 -0
- package/dist/src/utils/user_account.d.ts +9 -0
- package/dist/src/utils/user_account.js +99 -0
- package/dist/src/utils/user_account.js.map +1 -0
- package/dist/src/utils/user_account.test.d.ts +6 -0
- package/dist/src/utils/user_account.test.js +153 -0
- package/dist/src/utils/user_account.test.js.map +1 -0
- package/dist/src/utils/user_id.d.ts +11 -0
- package/dist/src/utils/user_id.js +49 -0
- package/dist/src/utils/user_id.js.map +1 -0
- package/dist/src/utils/user_id.test.d.ts +6 -0
- package/dist/src/utils/user_id.test.js +21 -0
- package/dist/src/utils/user_id.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/vybestack-llxprt-code-core-0.1.12.tgz +0 -0
- package/package.json +62 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { promises as fs } from 'node:fs';
|
|
8
|
+
import { getProjectTempDir, ensureLlxprtDirExists } from '../utils/paths.js';
|
|
9
|
+
const LOG_FILE_NAME = 'logs.json';
|
|
10
|
+
export var MessageSenderType;
|
|
11
|
+
(function (MessageSenderType) {
|
|
12
|
+
MessageSenderType["USER"] = "user";
|
|
13
|
+
})(MessageSenderType || (MessageSenderType = {}));
|
|
14
|
+
export class Logger {
|
|
15
|
+
llxprtDir;
|
|
16
|
+
logFilePath;
|
|
17
|
+
sessionId;
|
|
18
|
+
messageId = 0; // Instance-specific counter for the next messageId
|
|
19
|
+
initialized = false;
|
|
20
|
+
logs = []; // In-memory cache, ideally reflects the last known state of the file
|
|
21
|
+
constructor(sessionId) {
|
|
22
|
+
this.sessionId = sessionId;
|
|
23
|
+
}
|
|
24
|
+
async _readLogFile() {
|
|
25
|
+
if (!this.logFilePath) {
|
|
26
|
+
throw new Error('Log file path not set during read attempt.');
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const fileContent = await fs.readFile(this.logFilePath, 'utf-8');
|
|
30
|
+
const parsedLogs = JSON.parse(fileContent);
|
|
31
|
+
if (!Array.isArray(parsedLogs)) {
|
|
32
|
+
console.debug(`Log file at ${this.logFilePath} is not a valid JSON array. Starting with empty logs.`);
|
|
33
|
+
await this._backupCorruptedLogFile('malformed_array');
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
return parsedLogs.filter((entry) => typeof entry.sessionId === 'string' &&
|
|
37
|
+
typeof entry.messageId === 'number' &&
|
|
38
|
+
typeof entry.timestamp === 'string' &&
|
|
39
|
+
typeof entry.type === 'string' &&
|
|
40
|
+
typeof entry.message === 'string');
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const nodeError = error;
|
|
44
|
+
if (nodeError.code === 'ENOENT') {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
if (error instanceof SyntaxError) {
|
|
48
|
+
console.debug(`Invalid JSON in log file ${this.logFilePath}. Backing up and starting fresh.`, error);
|
|
49
|
+
await this._backupCorruptedLogFile('invalid_json');
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
console.debug(`Failed to read or parse log file ${this.logFilePath}:`, error);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async _backupCorruptedLogFile(reason) {
|
|
57
|
+
if (!this.logFilePath)
|
|
58
|
+
return;
|
|
59
|
+
const backupPath = `${this.logFilePath}.${reason}.${Date.now()}.bak`;
|
|
60
|
+
try {
|
|
61
|
+
await fs.rename(this.logFilePath, backupPath);
|
|
62
|
+
console.debug(`Backed up corrupted log file to ${backupPath}`);
|
|
63
|
+
}
|
|
64
|
+
catch (_backupError) {
|
|
65
|
+
// If rename fails (e.g. file doesn't exist), no need to log an error here as the primary error (e.g. invalid JSON) is already handled.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async initialize() {
|
|
69
|
+
if (this.initialized) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
ensureLlxprtDirExists();
|
|
73
|
+
this.llxprtDir = getProjectTempDir(process.cwd());
|
|
74
|
+
this.logFilePath = path.join(this.llxprtDir, LOG_FILE_NAME);
|
|
75
|
+
try {
|
|
76
|
+
await fs.mkdir(this.llxprtDir, { recursive: true });
|
|
77
|
+
let fileExisted = true;
|
|
78
|
+
try {
|
|
79
|
+
await fs.access(this.logFilePath);
|
|
80
|
+
}
|
|
81
|
+
catch (_e) {
|
|
82
|
+
fileExisted = false;
|
|
83
|
+
}
|
|
84
|
+
this.logs = await this._readLogFile();
|
|
85
|
+
if (!fileExisted && this.logs.length === 0) {
|
|
86
|
+
await fs.writeFile(this.logFilePath, '[]', 'utf-8');
|
|
87
|
+
}
|
|
88
|
+
const sessionLogs = this.logs.filter((entry) => entry.sessionId === this.sessionId);
|
|
89
|
+
this.messageId =
|
|
90
|
+
sessionLogs.length > 0
|
|
91
|
+
? Math.max(...sessionLogs.map((entry) => entry.messageId)) + 1
|
|
92
|
+
: 0;
|
|
93
|
+
this.initialized = true;
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.error('Failed to initialize logger:', err);
|
|
97
|
+
this.initialized = false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async _updateLogFile(entryToAppend) {
|
|
101
|
+
if (!this.logFilePath) {
|
|
102
|
+
console.debug('Log file path not set. Cannot persist log entry.');
|
|
103
|
+
throw new Error('Log file path not set during update attempt.');
|
|
104
|
+
}
|
|
105
|
+
let currentLogsOnDisk;
|
|
106
|
+
try {
|
|
107
|
+
currentLogsOnDisk = await this._readLogFile();
|
|
108
|
+
}
|
|
109
|
+
catch (readError) {
|
|
110
|
+
console.debug('Critical error reading log file before append:', readError);
|
|
111
|
+
throw readError;
|
|
112
|
+
}
|
|
113
|
+
// Determine the correct messageId for the new entry based on current disk state for its session
|
|
114
|
+
const sessionLogsOnDisk = currentLogsOnDisk.filter((e) => e.sessionId === entryToAppend.sessionId);
|
|
115
|
+
const nextMessageIdForSession = sessionLogsOnDisk.length > 0
|
|
116
|
+
? Math.max(...sessionLogsOnDisk.map((e) => e.messageId)) + 1
|
|
117
|
+
: 0;
|
|
118
|
+
// Update the messageId of the entry we are about to append
|
|
119
|
+
entryToAppend.messageId = nextMessageIdForSession;
|
|
120
|
+
// Check if this entry (same session, same *recalculated* messageId, same content) might already exist
|
|
121
|
+
// This is a stricter check for true duplicates if multiple instances try to log the exact same thing
|
|
122
|
+
// at the exact same calculated messageId slot.
|
|
123
|
+
const entryExists = currentLogsOnDisk.some((e) => e.sessionId === entryToAppend.sessionId &&
|
|
124
|
+
e.messageId === entryToAppend.messageId &&
|
|
125
|
+
e.timestamp === entryToAppend.timestamp && // Timestamps are good for distinguishing
|
|
126
|
+
e.message === entryToAppend.message);
|
|
127
|
+
if (entryExists) {
|
|
128
|
+
console.debug(`Duplicate log entry detected and skipped: session ${entryToAppend.sessionId}, messageId ${entryToAppend.messageId}`);
|
|
129
|
+
this.logs = currentLogsOnDisk; // Ensure in-memory is synced with disk
|
|
130
|
+
return null; // Indicate that no new entry was actually added
|
|
131
|
+
}
|
|
132
|
+
currentLogsOnDisk.push(entryToAppend);
|
|
133
|
+
try {
|
|
134
|
+
await fs.writeFile(this.logFilePath, JSON.stringify(currentLogsOnDisk, null, 2), 'utf-8');
|
|
135
|
+
this.logs = currentLogsOnDisk;
|
|
136
|
+
return entryToAppend; // Return the successfully appended entry
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.debug('Error writing to log file:', error);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async getPreviousUserMessages() {
|
|
144
|
+
if (!this.initialized)
|
|
145
|
+
return [];
|
|
146
|
+
return this.logs
|
|
147
|
+
.filter((entry) => entry.type === MessageSenderType.USER)
|
|
148
|
+
.sort((a, b) => {
|
|
149
|
+
const dateA = new Date(a.timestamp).getTime();
|
|
150
|
+
const dateB = new Date(b.timestamp).getTime();
|
|
151
|
+
return dateB - dateA;
|
|
152
|
+
})
|
|
153
|
+
.map((entry) => entry.message);
|
|
154
|
+
}
|
|
155
|
+
async logMessage(type, message) {
|
|
156
|
+
if (!this.initialized || this.sessionId === undefined) {
|
|
157
|
+
console.debug('Logger not initialized or session ID missing. Cannot log message.');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// The messageId used here is the instance's idea of the next ID.
|
|
161
|
+
// _updateLogFile will verify and potentially recalculate based on the file's actual state.
|
|
162
|
+
const newEntryObject = {
|
|
163
|
+
sessionId: this.sessionId,
|
|
164
|
+
messageId: this.messageId, // This will be recalculated in _updateLogFile
|
|
165
|
+
type,
|
|
166
|
+
message,
|
|
167
|
+
timestamp: new Date().toISOString(),
|
|
168
|
+
};
|
|
169
|
+
try {
|
|
170
|
+
const writtenEntry = await this._updateLogFile(newEntryObject);
|
|
171
|
+
if (writtenEntry) {
|
|
172
|
+
// If an entry was actually written (not a duplicate skip),
|
|
173
|
+
// then this instance can increment its idea of the next messageId for this session.
|
|
174
|
+
this.messageId = writtenEntry.messageId + 1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (_error) {
|
|
178
|
+
// Error already logged by _updateLogFile or _readLogFile
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
_checkpointPath(tag) {
|
|
182
|
+
if (!tag.length) {
|
|
183
|
+
throw new Error('No checkpoint tag specified.');
|
|
184
|
+
}
|
|
185
|
+
if (!this.llxprtDir) {
|
|
186
|
+
throw new Error('Checkpoint file path not set.');
|
|
187
|
+
}
|
|
188
|
+
return path.join(this.llxprtDir, `checkpoint-${tag}.json`);
|
|
189
|
+
}
|
|
190
|
+
async saveCheckpoint(conversation, tag, context) {
|
|
191
|
+
if (!this.initialized) {
|
|
192
|
+
console.error('Logger not initialized or checkpoint file path not set. Cannot save a checkpoint.');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const path = this._checkpointPath(tag);
|
|
196
|
+
try {
|
|
197
|
+
const data = JSON.stringify({ history: conversation, context }, null, 2);
|
|
198
|
+
await fs.writeFile(path, data, 'utf-8');
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
console.error('Error writing to checkpoint file:', error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async loadCheckpoint(tag) {
|
|
205
|
+
if (!this.initialized) {
|
|
206
|
+
console.error('Logger not initialized or checkpoint file path not set. Cannot load checkpoint.');
|
|
207
|
+
return { history: [] };
|
|
208
|
+
}
|
|
209
|
+
const path = this._checkpointPath(tag);
|
|
210
|
+
try {
|
|
211
|
+
const fileContent = await fs.readFile(path, 'utf-8');
|
|
212
|
+
const parsedContent = JSON.parse(fileContent);
|
|
213
|
+
if (Array.isArray(parsedContent)) {
|
|
214
|
+
// Backwards compatibility for old format
|
|
215
|
+
return { history: parsedContent };
|
|
216
|
+
}
|
|
217
|
+
return parsedContent;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
console.error(`Failed to read or parse checkpoint file ${path}:`, error);
|
|
221
|
+
const nodeError = error;
|
|
222
|
+
if (nodeError.code === 'ENOENT') {
|
|
223
|
+
// File doesn't exist, which is fine. Return empty.
|
|
224
|
+
return { history: [] };
|
|
225
|
+
}
|
|
226
|
+
return { history: [] };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
close() {
|
|
230
|
+
this.initialized = false;
|
|
231
|
+
this.logFilePath = undefined;
|
|
232
|
+
this.logs = [];
|
|
233
|
+
this.sessionId = undefined;
|
|
234
|
+
this.messageId = 0;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/core/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach, afterEach, afterAll, } from 'vitest';
|
|
7
|
+
import { Logger, MessageSenderType } from './logger.js';
|
|
8
|
+
import { promises as fs } from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import crypto from 'node:crypto';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
const LLXPRT_DIR_NAME = '.llxprt';
|
|
13
|
+
const TMP_DIR_NAME = 'tmp';
|
|
14
|
+
const LOG_FILE_NAME = 'logs.json';
|
|
15
|
+
const CHECKPOINT_FILE_NAME = 'checkpoint.json';
|
|
16
|
+
const projectDir = process.cwd();
|
|
17
|
+
const hash = crypto.createHash('sha256').update(projectDir).digest('hex');
|
|
18
|
+
const TEST_LLXPRT_DIR = path.join(os.homedir(), LLXPRT_DIR_NAME, TMP_DIR_NAME, hash);
|
|
19
|
+
const TEST_LOG_FILE_PATH = path.join(TEST_LLXPRT_DIR, LOG_FILE_NAME);
|
|
20
|
+
const TEST_CHECKPOINT_FILE_PATH = path.join(TEST_LLXPRT_DIR, CHECKPOINT_FILE_NAME);
|
|
21
|
+
async function cleanupLogAndCheckpointFiles() {
|
|
22
|
+
try {
|
|
23
|
+
await fs.rm(TEST_LLXPRT_DIR, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
catch (_error) {
|
|
26
|
+
// Ignore errors, as the directory may not exist, which is fine.
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function readLogFile() {
|
|
30
|
+
try {
|
|
31
|
+
const content = await fs.readFile(TEST_LOG_FILE_PATH, 'utf-8');
|
|
32
|
+
return JSON.parse(content);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error.code === 'ENOENT') {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
vi.mock('../utils/session.js', () => ({
|
|
42
|
+
sessionId: 'test-session-id',
|
|
43
|
+
}));
|
|
44
|
+
describe('Logger', () => {
|
|
45
|
+
let logger;
|
|
46
|
+
const testSessionId = 'test-session-id';
|
|
47
|
+
beforeEach(async () => {
|
|
48
|
+
vi.resetAllMocks();
|
|
49
|
+
vi.useFakeTimers();
|
|
50
|
+
vi.setSystemTime(new Date('2025-01-01T12:00:00.000Z'));
|
|
51
|
+
// Clean up before the test
|
|
52
|
+
await cleanupLogAndCheckpointFiles();
|
|
53
|
+
// Ensure the directory exists for the test
|
|
54
|
+
await fs.mkdir(TEST_LLXPRT_DIR, { recursive: true });
|
|
55
|
+
logger = new Logger(testSessionId);
|
|
56
|
+
await logger.initialize();
|
|
57
|
+
});
|
|
58
|
+
afterEach(async () => {
|
|
59
|
+
if (logger) {
|
|
60
|
+
logger.close();
|
|
61
|
+
}
|
|
62
|
+
// Clean up after the test
|
|
63
|
+
await cleanupLogAndCheckpointFiles();
|
|
64
|
+
vi.useRealTimers();
|
|
65
|
+
vi.restoreAllMocks();
|
|
66
|
+
});
|
|
67
|
+
afterAll(async () => {
|
|
68
|
+
// Final cleanup
|
|
69
|
+
await cleanupLogAndCheckpointFiles();
|
|
70
|
+
});
|
|
71
|
+
describe('initialize', () => {
|
|
72
|
+
it('should create .llxprt directory and an empty log file if none exist', async () => {
|
|
73
|
+
const dirExists = await fs
|
|
74
|
+
.access(TEST_LLXPRT_DIR)
|
|
75
|
+
.then(() => true)
|
|
76
|
+
.catch(() => false);
|
|
77
|
+
expect(dirExists).toBe(true);
|
|
78
|
+
const fileExists = await fs
|
|
79
|
+
.access(TEST_LOG_FILE_PATH)
|
|
80
|
+
.then(() => true)
|
|
81
|
+
.catch(() => false);
|
|
82
|
+
expect(fileExists).toBe(true);
|
|
83
|
+
const logContent = await readLogFile();
|
|
84
|
+
expect(logContent).toEqual([]);
|
|
85
|
+
});
|
|
86
|
+
it('should load existing logs and set correct messageId for the current session', async () => {
|
|
87
|
+
const currentSessionId = 'session-123';
|
|
88
|
+
const anotherSessionId = 'session-456';
|
|
89
|
+
const existingLogs = [
|
|
90
|
+
{
|
|
91
|
+
sessionId: currentSessionId,
|
|
92
|
+
messageId: 0,
|
|
93
|
+
timestamp: new Date('2025-01-01T10:00:05.000Z').toISOString(),
|
|
94
|
+
type: MessageSenderType.USER,
|
|
95
|
+
message: 'Msg1',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
sessionId: anotherSessionId,
|
|
99
|
+
messageId: 5,
|
|
100
|
+
timestamp: new Date('2025-01-01T09:00:00.000Z').toISOString(),
|
|
101
|
+
type: MessageSenderType.USER,
|
|
102
|
+
message: 'OldMsg',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
sessionId: currentSessionId,
|
|
106
|
+
messageId: 1,
|
|
107
|
+
timestamp: new Date('2025-01-01T10:00:10.000Z').toISOString(),
|
|
108
|
+
type: MessageSenderType.USER,
|
|
109
|
+
message: 'Msg2',
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
await fs.writeFile(TEST_LOG_FILE_PATH, JSON.stringify(existingLogs, null, 2));
|
|
113
|
+
const newLogger = new Logger(currentSessionId);
|
|
114
|
+
await newLogger.initialize();
|
|
115
|
+
expect(newLogger['messageId']).toBe(2);
|
|
116
|
+
expect(newLogger['logs']).toEqual(existingLogs);
|
|
117
|
+
newLogger.close();
|
|
118
|
+
});
|
|
119
|
+
it('should set messageId to 0 for a new session if log file exists but has no logs for current session', async () => {
|
|
120
|
+
const existingLogs = [
|
|
121
|
+
{
|
|
122
|
+
sessionId: 'some-other-session',
|
|
123
|
+
messageId: 5,
|
|
124
|
+
timestamp: new Date().toISOString(),
|
|
125
|
+
type: MessageSenderType.USER,
|
|
126
|
+
message: 'OldMsg',
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
await fs.writeFile(TEST_LOG_FILE_PATH, JSON.stringify(existingLogs, null, 2));
|
|
130
|
+
const newLogger = new Logger('a-new-session');
|
|
131
|
+
await newLogger.initialize();
|
|
132
|
+
expect(newLogger['messageId']).toBe(0);
|
|
133
|
+
newLogger.close();
|
|
134
|
+
});
|
|
135
|
+
it('should be idempotent', async () => {
|
|
136
|
+
await logger.logMessage(MessageSenderType.USER, 'test message');
|
|
137
|
+
const initialMessageId = logger['messageId'];
|
|
138
|
+
const initialLogCount = logger['logs'].length;
|
|
139
|
+
await logger.initialize(); // Second call should not change state
|
|
140
|
+
expect(logger['messageId']).toBe(initialMessageId);
|
|
141
|
+
expect(logger['logs'].length).toBe(initialLogCount);
|
|
142
|
+
const logsFromFile = await readLogFile();
|
|
143
|
+
expect(logsFromFile.length).toBe(1);
|
|
144
|
+
});
|
|
145
|
+
it('should handle invalid JSON in log file by backing it up and starting fresh', async () => {
|
|
146
|
+
await fs.writeFile(TEST_LOG_FILE_PATH, 'invalid json');
|
|
147
|
+
const consoleDebugSpy = vi
|
|
148
|
+
.spyOn(console, 'debug')
|
|
149
|
+
.mockImplementation(() => { });
|
|
150
|
+
const newLogger = new Logger(testSessionId);
|
|
151
|
+
await newLogger.initialize();
|
|
152
|
+
expect(consoleDebugSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid JSON in log file'), expect.any(SyntaxError));
|
|
153
|
+
const logContent = await readLogFile();
|
|
154
|
+
expect(logContent).toEqual([]);
|
|
155
|
+
const dirContents = await fs.readdir(TEST_LLXPRT_DIR);
|
|
156
|
+
expect(dirContents.some((f) => f.startsWith(LOG_FILE_NAME + '.invalid_json') && f.endsWith('.bak'))).toBe(true);
|
|
157
|
+
newLogger.close();
|
|
158
|
+
});
|
|
159
|
+
it('should handle non-array JSON in log file by backing it up and starting fresh', async () => {
|
|
160
|
+
await fs.writeFile(TEST_LOG_FILE_PATH, JSON.stringify({ not: 'an array' }));
|
|
161
|
+
const consoleDebugSpy = vi
|
|
162
|
+
.spyOn(console, 'debug')
|
|
163
|
+
.mockImplementation(() => { });
|
|
164
|
+
const newLogger = new Logger(testSessionId);
|
|
165
|
+
await newLogger.initialize();
|
|
166
|
+
expect(consoleDebugSpy).toHaveBeenCalledWith(`Log file at ${TEST_LOG_FILE_PATH} is not a valid JSON array. Starting with empty logs.`);
|
|
167
|
+
const logContent = await readLogFile();
|
|
168
|
+
expect(logContent).toEqual([]);
|
|
169
|
+
const dirContents = await fs.readdir(TEST_LLXPRT_DIR);
|
|
170
|
+
expect(dirContents.some((f) => f.startsWith(LOG_FILE_NAME + '.malformed_array') &&
|
|
171
|
+
f.endsWith('.bak'))).toBe(true);
|
|
172
|
+
newLogger.close();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('logMessage', () => {
|
|
176
|
+
it('should append a message to the log file and update in-memory logs', async () => {
|
|
177
|
+
await logger.logMessage(MessageSenderType.USER, 'Hello, world!');
|
|
178
|
+
const logsFromFile = await readLogFile();
|
|
179
|
+
expect(logsFromFile.length).toBe(1);
|
|
180
|
+
expect(logsFromFile[0]).toMatchObject({
|
|
181
|
+
sessionId: testSessionId,
|
|
182
|
+
messageId: 0,
|
|
183
|
+
type: MessageSenderType.USER,
|
|
184
|
+
message: 'Hello, world!',
|
|
185
|
+
timestamp: new Date('2025-01-01T12:00:00.000Z').toISOString(),
|
|
186
|
+
});
|
|
187
|
+
expect(logger['logs'].length).toBe(1);
|
|
188
|
+
expect(logger['logs'][0]).toEqual(logsFromFile[0]);
|
|
189
|
+
expect(logger['messageId']).toBe(1);
|
|
190
|
+
});
|
|
191
|
+
it('should correctly increment messageId for subsequent messages in the same session', async () => {
|
|
192
|
+
await logger.logMessage(MessageSenderType.USER, 'First');
|
|
193
|
+
vi.advanceTimersByTime(1000);
|
|
194
|
+
await logger.logMessage(MessageSenderType.USER, 'Second');
|
|
195
|
+
const logs = await readLogFile();
|
|
196
|
+
expect(logs.length).toBe(2);
|
|
197
|
+
expect(logs[0].messageId).toBe(0);
|
|
198
|
+
expect(logs[1].messageId).toBe(1);
|
|
199
|
+
expect(logs[1].timestamp).not.toBe(logs[0].timestamp);
|
|
200
|
+
expect(logger['messageId']).toBe(2);
|
|
201
|
+
});
|
|
202
|
+
it('should handle logger not initialized', async () => {
|
|
203
|
+
const uninitializedLogger = new Logger(testSessionId);
|
|
204
|
+
uninitializedLogger.close(); // Ensure it's treated as uninitialized
|
|
205
|
+
const consoleDebugSpy = vi
|
|
206
|
+
.spyOn(console, 'debug')
|
|
207
|
+
.mockImplementation(() => { });
|
|
208
|
+
await uninitializedLogger.logMessage(MessageSenderType.USER, 'test');
|
|
209
|
+
expect(consoleDebugSpy).toHaveBeenCalledWith('Logger not initialized or session ID missing. Cannot log message.');
|
|
210
|
+
expect((await readLogFile()).length).toBe(0);
|
|
211
|
+
uninitializedLogger.close();
|
|
212
|
+
});
|
|
213
|
+
it('should simulate concurrent writes from different logger instances to the same file', async () => {
|
|
214
|
+
const concurrentSessionId = 'concurrent-session';
|
|
215
|
+
const logger1 = new Logger(concurrentSessionId);
|
|
216
|
+
await logger1.initialize();
|
|
217
|
+
const logger2 = new Logger(concurrentSessionId);
|
|
218
|
+
await logger2.initialize();
|
|
219
|
+
expect(logger2['sessionId']).toEqual(logger1['sessionId']);
|
|
220
|
+
await logger1.logMessage(MessageSenderType.USER, 'L1M1');
|
|
221
|
+
vi.advanceTimersByTime(10);
|
|
222
|
+
await logger2.logMessage(MessageSenderType.USER, 'L2M1');
|
|
223
|
+
vi.advanceTimersByTime(10);
|
|
224
|
+
await logger1.logMessage(MessageSenderType.USER, 'L1M2');
|
|
225
|
+
vi.advanceTimersByTime(10);
|
|
226
|
+
await logger2.logMessage(MessageSenderType.USER, 'L2M2');
|
|
227
|
+
const logsFromFile = await readLogFile();
|
|
228
|
+
expect(logsFromFile.length).toBe(4);
|
|
229
|
+
const messageIdsInFile = logsFromFile
|
|
230
|
+
.map((log) => log.messageId)
|
|
231
|
+
.sort((a, b) => a - b);
|
|
232
|
+
expect(messageIdsInFile).toEqual([0, 1, 2, 3]);
|
|
233
|
+
const messagesInFile = logsFromFile
|
|
234
|
+
.sort((a, b) => a.messageId - b.messageId)
|
|
235
|
+
.map((l) => l.message);
|
|
236
|
+
expect(messagesInFile).toEqual(['L1M1', 'L2M1', 'L1M2', 'L2M2']);
|
|
237
|
+
// Check internal state (next messageId each logger would use for that session)
|
|
238
|
+
expect(logger1['messageId']).toBe(3);
|
|
239
|
+
expect(logger2['messageId']).toBe(4);
|
|
240
|
+
logger1.close();
|
|
241
|
+
logger2.close();
|
|
242
|
+
});
|
|
243
|
+
it('should not throw, not increment messageId, and log error if writing to file fails', async () => {
|
|
244
|
+
vi.spyOn(fs, 'writeFile').mockRejectedValueOnce(new Error('Disk full'));
|
|
245
|
+
const consoleDebugSpy = vi
|
|
246
|
+
.spyOn(console, 'debug')
|
|
247
|
+
.mockImplementation(() => { });
|
|
248
|
+
const initialMessageId = logger['messageId'];
|
|
249
|
+
const initialLogCount = logger['logs'].length;
|
|
250
|
+
await logger.logMessage(MessageSenderType.USER, 'test fail write');
|
|
251
|
+
expect(consoleDebugSpy).toHaveBeenCalledWith('Error writing to log file:', expect.any(Error));
|
|
252
|
+
expect(logger['messageId']).toBe(initialMessageId); // Not incremented
|
|
253
|
+
expect(logger['logs'].length).toBe(initialLogCount); // Log not added to in-memory cache
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
describe('getPreviousUserMessages', () => {
|
|
257
|
+
it('should retrieve all user messages from logs, sorted newest first', async () => {
|
|
258
|
+
const loggerSort = new Logger('session-1');
|
|
259
|
+
await loggerSort.initialize();
|
|
260
|
+
await loggerSort.logMessage(MessageSenderType.USER, 'S1M0_ts100000');
|
|
261
|
+
vi.advanceTimersByTime(1000);
|
|
262
|
+
await loggerSort.logMessage(MessageSenderType.USER, 'S1M1_ts101000');
|
|
263
|
+
vi.advanceTimersByTime(1000);
|
|
264
|
+
// Switch to a different session to log
|
|
265
|
+
const loggerSort2 = new Logger('session-2');
|
|
266
|
+
await loggerSort2.initialize();
|
|
267
|
+
await loggerSort2.logMessage(MessageSenderType.USER, 'S2M0_ts102000');
|
|
268
|
+
vi.advanceTimersByTime(1000);
|
|
269
|
+
await loggerSort2.logMessage('model', 'S2_Model_ts103000');
|
|
270
|
+
vi.advanceTimersByTime(1000);
|
|
271
|
+
await loggerSort2.logMessage(MessageSenderType.USER, 'S2M1_ts104000');
|
|
272
|
+
loggerSort.close();
|
|
273
|
+
loggerSort2.close();
|
|
274
|
+
const finalLogger = new Logger('final-session');
|
|
275
|
+
await finalLogger.initialize();
|
|
276
|
+
const messages = await finalLogger.getPreviousUserMessages();
|
|
277
|
+
expect(messages).toEqual([
|
|
278
|
+
'S2M1_ts104000',
|
|
279
|
+
'S2M0_ts102000',
|
|
280
|
+
'S1M1_ts101000',
|
|
281
|
+
'S1M0_ts100000',
|
|
282
|
+
]);
|
|
283
|
+
finalLogger.close();
|
|
284
|
+
});
|
|
285
|
+
it('should return empty array if no user messages exist', async () => {
|
|
286
|
+
await logger.logMessage('system', 'System boot');
|
|
287
|
+
const messages = await logger.getPreviousUserMessages();
|
|
288
|
+
expect(messages).toEqual([]);
|
|
289
|
+
});
|
|
290
|
+
it('should return empty array if logger not initialized', async () => {
|
|
291
|
+
const uninitializedLogger = new Logger(testSessionId);
|
|
292
|
+
uninitializedLogger.close();
|
|
293
|
+
const messages = await uninitializedLogger.getPreviousUserMessages();
|
|
294
|
+
expect(messages).toEqual([]);
|
|
295
|
+
uninitializedLogger.close();
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
describe('saveCheckpoint', () => {
|
|
299
|
+
const conversation = [
|
|
300
|
+
{ role: 'user', parts: [{ text: 'Hello' }] },
|
|
301
|
+
{ role: 'model', parts: [{ text: 'Hi there' }] },
|
|
302
|
+
];
|
|
303
|
+
it('should save a checkpoint to a tagged file when a tag is provided', async () => {
|
|
304
|
+
const tag = 'my-test-tag';
|
|
305
|
+
await logger.saveCheckpoint(conversation, tag);
|
|
306
|
+
const taggedFilePath = path.join(TEST_LLXPRT_DIR, `${CHECKPOINT_FILE_NAME.replace('.json', '')}-${tag}.json`);
|
|
307
|
+
const fileContent = await fs.readFile(taggedFilePath, 'utf-8');
|
|
308
|
+
expect(JSON.parse(fileContent)).toEqual({ history: conversation });
|
|
309
|
+
});
|
|
310
|
+
it('should not throw if logger is not initialized', async () => {
|
|
311
|
+
const uninitializedLogger = new Logger(testSessionId);
|
|
312
|
+
uninitializedLogger.close();
|
|
313
|
+
const consoleErrorSpy = vi
|
|
314
|
+
.spyOn(console, 'error')
|
|
315
|
+
.mockImplementation(() => { });
|
|
316
|
+
await expect(uninitializedLogger.saveCheckpoint(conversation, 'tag')).resolves.not.toThrow();
|
|
317
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Logger not initialized or checkpoint file path not set. Cannot save a checkpoint.');
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
describe('loadCheckpoint', () => {
|
|
321
|
+
const conversation = [
|
|
322
|
+
{ role: 'user', parts: [{ text: 'Hello' }] },
|
|
323
|
+
{ role: 'model', parts: [{ text: 'Hi there' }] },
|
|
324
|
+
];
|
|
325
|
+
beforeEach(async () => {
|
|
326
|
+
await fs.writeFile(TEST_CHECKPOINT_FILE_PATH, JSON.stringify(conversation, null, 2));
|
|
327
|
+
});
|
|
328
|
+
it('should load from a tagged checkpoint file when a tag is provided', async () => {
|
|
329
|
+
const tag = 'my-load-tag';
|
|
330
|
+
const taggedConversation = [
|
|
331
|
+
...conversation,
|
|
332
|
+
{ role: 'user', parts: [{ text: 'Another message' }] },
|
|
333
|
+
];
|
|
334
|
+
const taggedFilePath = path.join(TEST_LLXPRT_DIR, `${CHECKPOINT_FILE_NAME.replace('.json', '')}-${tag}.json`);
|
|
335
|
+
await fs.writeFile(taggedFilePath, JSON.stringify(taggedConversation, null, 2));
|
|
336
|
+
const loaded = await logger.loadCheckpoint(tag);
|
|
337
|
+
expect(loaded).toEqual({ history: taggedConversation });
|
|
338
|
+
});
|
|
339
|
+
it('should return an empty array if a tagged checkpoint file does not exist', async () => {
|
|
340
|
+
const loaded = await logger.loadCheckpoint('non-existent-tag');
|
|
341
|
+
expect(loaded).toEqual({ history: [] });
|
|
342
|
+
});
|
|
343
|
+
it('should return an empty array if the checkpoint file does not exist', async () => {
|
|
344
|
+
await fs.unlink(TEST_CHECKPOINT_FILE_PATH); // Ensure it's gone
|
|
345
|
+
const loaded = await logger.loadCheckpoint('missing');
|
|
346
|
+
expect(loaded).toEqual({ history: [] });
|
|
347
|
+
});
|
|
348
|
+
it('should return an empty array if the file contains invalid JSON', async () => {
|
|
349
|
+
await fs.writeFile(TEST_CHECKPOINT_FILE_PATH, 'invalid json');
|
|
350
|
+
const consoleErrorSpy = vi
|
|
351
|
+
.spyOn(console, 'error')
|
|
352
|
+
.mockImplementation(() => { });
|
|
353
|
+
const loadedCheckpoint = await logger.loadCheckpoint('missing');
|
|
354
|
+
expect(loadedCheckpoint).toEqual({ history: [] });
|
|
355
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Failed to read or parse checkpoint file'), expect.any(Error));
|
|
356
|
+
});
|
|
357
|
+
it('should return an empty array if logger is not initialized', async () => {
|
|
358
|
+
const uninitializedLogger = new Logger(testSessionId);
|
|
359
|
+
uninitializedLogger.close();
|
|
360
|
+
const consoleErrorSpy = vi
|
|
361
|
+
.spyOn(console, 'error')
|
|
362
|
+
.mockImplementation(() => { });
|
|
363
|
+
const loadedCheckpoint = await uninitializedLogger.loadCheckpoint('tag');
|
|
364
|
+
expect(loadedCheckpoint).toEqual({ history: [] });
|
|
365
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Logger not initialized or checkpoint file path not set. Cannot load checkpoint.');
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
describe('close', () => {
|
|
369
|
+
it('should reset logger state', async () => {
|
|
370
|
+
await logger.logMessage(MessageSenderType.USER, 'A message');
|
|
371
|
+
logger.close();
|
|
372
|
+
const consoleDebugSpy = vi
|
|
373
|
+
.spyOn(console, 'debug')
|
|
374
|
+
.mockImplementation(() => { });
|
|
375
|
+
await logger.logMessage(MessageSenderType.USER, 'Another message');
|
|
376
|
+
expect(consoleDebugSpy).toHaveBeenCalledWith('Logger not initialized or session ID missing. Cannot log message.');
|
|
377
|
+
const messages = await logger.getPreviousUserMessages();
|
|
378
|
+
expect(messages).toEqual([]);
|
|
379
|
+
expect(logger['initialized']).toBe(false);
|
|
380
|
+
expect(logger['logFilePath']).toBeUndefined();
|
|
381
|
+
expect(logger['logs']).toEqual([]);
|
|
382
|
+
expect(logger['sessionId']).toBeUndefined();
|
|
383
|
+
expect(logger['messageId']).toBe(0);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
//# sourceMappingURL=logger.test.js.map
|