@gitkraken/core-gitlens 0.5.110 → 0.5.112
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/CHANGELOG.md +19 -1
- package/dist/git/cache.d.ts +111 -6
- package/dist/git/cache.d.ts.map +1 -1
- package/dist/git/cache.js +312 -43
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +11 -0
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/models/fileStatus.d.ts +1 -0
- package/dist/git/models/fileStatus.d.ts.map +1 -1
- package/dist/git/models/fileStatus.js +1 -0
- package/dist/git/models/fileStatus.js.map +1 -1
- package/dist/git/models/issue.d.ts +4 -0
- package/dist/git/models/issue.d.ts.map +1 -1
- package/dist/git/models/mergeConflicts.d.ts +2 -0
- package/dist/git/models/mergeConflicts.d.ts.map +1 -1
- package/dist/git/models/pullRequest.d.ts +38 -2
- package/dist/git/models/pullRequest.d.ts.map +1 -1
- package/dist/git/models/pullRequest.js +12 -1
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/models/repository.d.ts +32 -5
- package/dist/git/models/repository.d.ts.map +1 -1
- package/dist/git/models/repository.js +58 -12
- package/dist/git/models/repository.js.map +1 -1
- package/dist/git/models/statusFile.d.ts.map +1 -1
- package/dist/git/models/statusFile.js +3 -0
- package/dist/git/models/statusFile.js.map +1 -1
- package/dist/git/providers/branches.d.ts +2 -0
- package/dist/git/providers/branches.d.ts.map +1 -1
- package/dist/git/providers/commits.d.ts +8 -0
- package/dist/git/providers/commits.d.ts.map +1 -1
- package/dist/git/providers/config.d.ts +19 -1
- package/dist/git/providers/config.d.ts.map +1 -1
- package/dist/git/providers/operations.d.ts +1 -0
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/pausedOperations.d.ts +2 -0
- package/dist/git/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git/providers/status.d.ts +1 -0
- package/dist/git/providers/status.d.ts.map +1 -1
- package/dist/git/utils/config.utils.d.ts +3 -0
- package/dist/git/utils/config.utils.d.ts.map +1 -0
- package/dist/git/utils/config.utils.js +8 -0
- package/dist/git/utils/config.utils.js.map +1 -0
- package/dist/git/utils/issue.utils.d.ts.map +1 -1
- package/dist/git/utils/issue.utils.js +2 -0
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pausedOperationStatus.utils.d.ts +14 -0
- package/dist/git/utils/pausedOperationStatus.utils.d.ts.map +1 -1
- package/dist/git/utils/pausedOperationStatus.utils.js +23 -0
- package/dist/git/utils/pausedOperationStatus.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.d.ts +14 -1
- package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
- package/dist/git/utils/pullRequest.utils.js +31 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/git/watching/changeEvent.d.ts +6 -1
- package/dist/git/watching/changeEvent.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.js +14 -1
- package/dist/git/watching/classifyChange.js.map +1 -1
- package/dist/git/watching/watchService.d.ts.map +1 -1
- package/dist/git/watching/watchService.js +18 -3
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +8 -1
- package/dist/git/watching/watchSession.d.ts.map +1 -1
- package/dist/git/watching/watchSession.js +38 -6
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git/watching/watcherPatterns.d.ts +2 -2
- package/dist/git/watching/watcherPatterns.d.ts.map +1 -1
- package/dist/git/watching/watcherPatterns.js +1 -1
- package/dist/git/watching/watcherPatterns.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +1 -1
- package/dist/git-cli/exec/git.d.ts.map +1 -1
- package/dist/git-cli/exec/git.js +13 -3
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +19 -0
- package/dist/git-cli/providers/branches.d.ts.map +1 -1
- package/dist/git-cli/providers/branches.js +282 -78
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +4 -0
- package/dist/git-cli/providers/commits.d.ts.map +1 -1
- package/dist/git-cli/providers/commits.js +84 -11
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +42 -0
- package/dist/git-cli/providers/config.d.ts.map +1 -1
- package/dist/git-cli/providers/config.js +186 -5
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/contributors.d.ts.map +1 -1
- package/dist/git-cli/providers/contributors.js +1 -1
- package/dist/git-cli/providers/contributors.js.map +1 -1
- package/dist/git-cli/providers/graph.d.ts +2 -2
- package/dist/git-cli/providers/graph.d.ts.map +1 -1
- package/dist/git-cli/providers/graph.js +27 -9
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +40 -12
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +5 -0
- package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +87 -16
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +5 -3
- package/dist/git-cli/providers/refs.d.ts.map +1 -1
- package/dist/git-cli/providers/refs.js +33 -4
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +1 -0
- package/dist/git-cli/providers/status.d.ts.map +1 -1
- package/dist/git-cli/providers/status.js +18 -3
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
- package/dist/git-cli/providers/worktrees.js +4 -0
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.d.ts.map +1 -1
- package/dist/git-cli/service.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts +39 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.js +978 -71
- package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +24 -2
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +84 -9
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/agents/types.d.ts +37 -2
- package/dist/plus/agents/types.d.ts.map +1 -1
- package/dist/plus/agents/types.js +2 -0
- package/dist/plus/agents/types.js.map +1 -1
- package/dist/plus/ai/errors.d.ts +10 -0
- package/dist/plus/ai/errors.d.ts.map +1 -1
- package/dist/plus/ai/errors.js +29 -0
- package/dist/plus/ai/errors.js.map +1 -1
- package/dist/plus/ai/models/model.d.ts +4 -0
- package/dist/plus/ai/models/model.d.ts.map +1 -1
- package/dist/plus/ai/models/model.js +51 -6
- package/dist/plus/ai/models/model.js.map +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
- package/dist/plus/ai/models/provider.d.ts +60 -2
- package/dist/plus/ai/models/provider.d.ts.map +1 -1
- package/dist/plus/ai/prompts.d.ts +12 -0
- package/dist/plus/ai/prompts.d.ts.map +1 -1
- package/dist/plus/ai/prompts.js +177 -61
- package/dist/plus/ai/prompts.js.map +1 -1
- package/dist/plus/ai/providers/anthropicProvider.d.ts +10 -2
- package/dist/plus/ai/providers/anthropicProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/anthropicProvider.js +139 -46
- package/dist/plus/ai/providers/anthropicProvider.js.map +1 -1
- package/dist/plus/ai/providers/deepSeekProvider.d.ts +2 -0
- package/dist/plus/ai/providers/deepSeekProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/deepSeekProvider.js +10 -21
- package/dist/plus/ai/providers/deepSeekProvider.js.map +1 -1
- package/dist/plus/ai/providers/geminiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/geminiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/geminiProvider.js +19 -0
- package/dist/plus/ai/providers/geminiProvider.js.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts +5 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js +118 -3
- package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
- package/dist/plus/ai/providers/huggingFaceProvider.d.ts +1 -0
- package/dist/plus/ai/providers/huggingFaceProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/huggingFaceProvider.js +5 -0
- package/dist/plus/ai/providers/huggingFaceProvider.js.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.d.ts +3 -1
- package/dist/plus/ai/providers/mistralProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.js +99 -19
- package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
- package/dist/plus/ai/providers/ollamaProvider.d.ts +4 -3
- package/dist/plus/ai/providers/ollamaProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/ollamaProvider.js +38 -3
- package/dist/plus/ai/providers/ollamaProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProvider.d.ts +1 -0
- package/dist/plus/ai/providers/openAICompatibleProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProvider.js +4 -0
- package/dist/plus/ai/providers/openAICompatibleProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +154 -5
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +259 -10
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/ai/providers/openRouterProvider.d.ts +4 -0
- package/dist/plus/ai/providers/openRouterProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openRouterProvider.js +9 -0
- package/dist/plus/ai/providers/openRouterProvider.js.map +1 -1
- package/dist/plus/ai/providers/openaiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/openaiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openaiProvider.js +1 -0
- package/dist/plus/ai/providers/openaiProvider.js.map +1 -1
- package/dist/plus/ai/providers/responseFormatCache.d.ts +8 -0
- package/dist/plus/ai/providers/responseFormatCache.d.ts.map +1 -0
- package/dist/plus/ai/providers/responseFormatCache.js +25 -0
- package/dist/plus/ai/providers/responseFormatCache.js.map +1 -0
- package/dist/plus/ai/providers/xaiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/xaiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/xaiProvider.js +10 -1
- package/dist/plus/ai/providers/xaiProvider.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.d.ts +3 -0
- package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +13 -0
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/ai/utils/results.utils.d.ts +16 -2
- package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/results.utils.js +204 -28
- package/dist/plus/ai/utils/results.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +55 -0
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +177 -4
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +16 -0
- package/dist/plus/git-github/models.d.ts.map +1 -1
- package/dist/plus/git-github/models.js +29 -3
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/git-github/providers/github/status.d.ts +1 -0
- package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/status.js.map +1 -1
- package/dist/plus/integrations/context.d.ts +4 -0
- package/dist/plus/integrations/context.d.ts.map +1 -1
- package/dist/plus/integrations/index.d.ts.map +1 -1
- package/dist/plus/integrations/index.js +2 -0
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +6 -3
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +12 -2
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +3 -1
- package/dist/plus/integrations/models/integration.d.ts.map +1 -1
- package/dist/plus/integrations/models/integration.js +2 -2
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/providers/accounts.d.ts.map +1 -1
- package/dist/plus/integrations/providers/accounts.js +4 -0
- package/dist/plus/integrations/providers/accounts.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/azure/models.js +3 -0
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +14 -2
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +55 -3
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +30 -4
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
- package/dist/plus/integrations/reads/broaden.js +6 -1
- package/dist/plus/integrations/reads/broaden.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
- package/dist/plus/integrations/reads/drains.js +7 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.d.ts.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +3 -1
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +8 -3
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issues.js +9 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.d.ts.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.js +9 -4
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/utils/env/browser/base64.d.ts +1 -1
- package/dist/utils/env/browser/base64.d.ts.map +1 -1
- package/dist/utils/env/node/base64.d.ts +1 -1
- package/dist/utils/env/node/base64.d.ts.map +1 -1
- package/dist/utils/env/node/base64.js +2 -0
- package/dist/utils/env/node/base64.js.map +1 -1
- package/dist/utils/keys/chord.d.ts +52 -0
- package/dist/utils/keys/chord.d.ts.map +1 -0
- package/dist/utils/keys/chord.js +135 -0
- package/dist/utils/keys/chord.js.map +1 -0
- package/dist/utils/keys/keybinding.d.ts +53 -0
- package/dist/utils/keys/keybinding.d.ts.map +1 -0
- package/dist/utils/keys/keybinding.js +58 -0
- package/dist/utils/keys/keybinding.js.map +1 -0
- package/dist/utils/path.d.ts +11 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +13 -0
- package/dist/utils/path.js.map +1 -1
- package/package.json +13 -5
- package/src/git/cache.ts +383 -47
- package/src/git/context.ts +11 -0
- package/src/git/models/fileStatus.ts +1 -0
- package/src/git/models/issue.ts +4 -0
- package/src/git/models/mergeConflicts.ts +3 -2
- package/src/git/models/pullRequest.ts +33 -1
- package/src/git/models/repository.ts +58 -17
- package/src/git/models/statusFile.ts +3 -0
- package/src/git/providers/branches.ts +6 -0
- package/src/git/providers/commits.ts +11 -0
- package/src/git/providers/config.ts +18 -0
- package/src/git/providers/operations.ts +1 -0
- package/src/git/providers/pausedOperations.ts +2 -0
- package/src/git/providers/status.ts +1 -0
- package/src/git/utils/config.utils.ts +8 -0
- package/src/git/utils/issue.utils.ts +2 -0
- package/src/git/utils/pausedOperationStatus.utils.ts +28 -0
- package/src/git/utils/pullRequest.utils.ts +36 -0
- package/src/git/watching/changeEvent.ts +6 -1
- package/src/git/watching/classifyChange.ts +15 -1
- package/src/git/watching/watchService.ts +20 -3
- package/src/git/watching/watchSession.ts +41 -6
- package/src/git/watching/watcherPatterns.ts +1 -1
- package/src/git-cli/exec/git.ts +13 -3
- package/src/git-cli/providers/branches.ts +384 -132
- package/src/git-cli/providers/commits.ts +106 -15
- package/src/git-cli/providers/config.ts +229 -8
- package/src/git-cli/providers/contributors.ts +5 -1
- package/src/git-cli/providers/graph.ts +26 -13
- package/src/git-cli/providers/operations.ts +45 -20
- package/src/git-cli/providers/pausedOperations.ts +109 -17
- package/src/git-cli/providers/refs.ts +33 -3
- package/src/git-cli/providers/status.ts +25 -4
- package/src/git-cli/providers/worktrees.ts +5 -0
- package/src/git-cli/service.ts +0 -1
- package/src/plus/agents/providers/claudeCodeProvider.ts +1130 -87
- package/src/plus/agents/providers/claudeCodeTranscript.ts +95 -9
- package/src/plus/agents/types.ts +46 -2
- package/src/plus/ai/errors.ts +30 -0
- package/src/plus/ai/models/model.ts +56 -6
- package/src/plus/ai/models/promptTemplates.ts +1 -1
- package/src/plus/ai/models/provider.ts +69 -2
- package/src/plus/ai/prompts.ts +186 -61
- package/src/plus/ai/providers/anthropicProvider.ts +155 -47
- package/src/plus/ai/providers/deepSeekProvider.ts +11 -21
- package/src/plus/ai/providers/geminiProvider.ts +19 -0
- package/src/plus/ai/providers/gitkrakenProvider.ts +126 -3
- package/src/plus/ai/providers/huggingFaceProvider.ts +6 -0
- package/src/plus/ai/providers/mistralProvider.ts +102 -19
- package/src/plus/ai/providers/ollamaProvider.ts +55 -4
- package/src/plus/ai/providers/openAICompatibleProvider.ts +5 -0
- package/src/plus/ai/providers/openAICompatibleProviderBase.ts +360 -17
- package/src/plus/ai/providers/openRouterProvider.ts +17 -0
- package/src/plus/ai/providers/openaiProvider.ts +1 -0
- package/src/plus/ai/providers/responseFormatCache.ts +39 -0
- package/src/plus/ai/providers/xaiProvider.ts +10 -1
- package/src/plus/ai/utils/ai.utils.ts +14 -0
- package/src/plus/ai/utils/results.utils.ts +255 -31
- package/src/plus/git-github/api/github.ts +291 -7
- package/src/plus/git-github/models.ts +48 -2
- package/src/plus/git-github/providers/github/status.ts +1 -0
- package/src/plus/integrations/context.ts +4 -0
- package/src/plus/integrations/index.ts +2 -0
- package/src/plus/integrations/models/gitHostIntegration.ts +25 -2
- package/src/plus/integrations/models/integration.ts +23 -13
- package/src/plus/integrations/providers/accounts.ts +4 -0
- package/src/plus/integrations/providers/azure/models.ts +3 -0
- package/src/plus/integrations/providers/bitbucket/models.ts +1 -0
- package/src/plus/integrations/providers/github.ts +85 -1
- package/src/plus/integrations/providers/gitlab.ts +2 -10
- package/src/plus/integrations/providers/models.ts +36 -4
- package/src/plus/integrations/reads/broaden.ts +6 -1
- package/src/plus/integrations/reads/drains.ts +7 -4
- package/src/plus/integrations/reads/hierarchy.ts +3 -1
- package/src/plus/integrations/reads/issueTracker.ts +9 -3
- package/src/plus/integrations/reads/issues.ts +9 -4
- package/src/plus/integrations/reads/pullRequests.ts +9 -4
- package/src/utils/env/browser/base64.ts +1 -1
- package/src/utils/env/node/base64.ts +3 -1
- package/src/utils/keys/chord.ts +184 -0
- package/src/utils/keys/keybinding.ts +116 -0
- package/src/utils/path.ts +14 -0
|
@@ -76,15 +76,25 @@ function parseSeverity(value: string | undefined): AIReviewSeverity {
|
|
|
76
76
|
return 'suggestion';
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/** Shared range policy for the XML and JSON parse routes: no usable start → no range; a missing
|
|
80
|
+
* or unusable end collapses to start */
|
|
81
|
+
function normalizeLineRange(
|
|
82
|
+
start: number | undefined,
|
|
83
|
+
end: number | undefined,
|
|
84
|
+
): { start: number; end: number } | undefined {
|
|
85
|
+
if (start == null || !Number.isFinite(start)) return undefined;
|
|
86
|
+
|
|
87
|
+
// Truncate and clamp — prompt-only providers can emit fractional or reversed bounds
|
|
88
|
+
start = Math.trunc(start);
|
|
89
|
+
const resolved = end != null && Number.isFinite(end) ? Math.trunc(end) : start;
|
|
90
|
+
return { start: start, end: Math.max(start, resolved) };
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
function parseLineRange(value: string | undefined): { start: number; end: number } | undefined {
|
|
80
94
|
if (!value) return undefined;
|
|
81
95
|
|
|
82
96
|
const parts = value.split('-');
|
|
83
|
-
|
|
84
|
-
if (isNaN(start)) return undefined;
|
|
85
|
-
|
|
86
|
-
const end = parts.length > 1 ? parseInt(parts[1], 10) : start;
|
|
87
|
-
return { start: start, end: isNaN(end) ? start : end };
|
|
97
|
+
return normalizeLineRange(parseInt(parts[0], 10), parts.length > 1 ? parseInt(parts[1], 10) : undefined);
|
|
88
98
|
}
|
|
89
99
|
|
|
90
100
|
function parseFindings(content: string, idPrefix: string): AIReviewFinding[] {
|
|
@@ -141,36 +151,32 @@ export function parseReviewResult(result: string, mode: 'single-pass' | 'two-pas
|
|
|
141
151
|
return { overview: overview, focusAreas: focusAreas, mode: mode };
|
|
142
152
|
}
|
|
143
153
|
|
|
144
|
-
function
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
attrs.push(`file="${serializeAttrValue(finding.filePath)}"`);
|
|
153
|
-
}
|
|
154
|
-
if (finding.lineRange != null) {
|
|
155
|
-
attrs.push(`lines="${finding.lineRange.start}-${finding.lineRange.end}"`);
|
|
156
|
-
}
|
|
157
|
-
return `<finding ${attrs.join(' ')}>\n<title>${finding.title}</title>\n<description>${finding.description}</description>\n</finding>`;
|
|
154
|
+
function serializeFindingJson(finding: AIReviewFinding): ReviewFindingJson {
|
|
155
|
+
return {
|
|
156
|
+
severity: finding.severity,
|
|
157
|
+
title: finding.title,
|
|
158
|
+
description: finding.description,
|
|
159
|
+
file: finding.filePath ?? null,
|
|
160
|
+
lines: finding.lineRange != null ? { start: finding.lineRange.start, end: finding.lineRange.end } : null,
|
|
161
|
+
};
|
|
158
162
|
}
|
|
159
163
|
|
|
160
|
-
/** Inverse of {@link
|
|
161
|
-
* so a prior result can be replayed as an assistant turn in a
|
|
164
|
+
/** Inverse of {@link parseReviewResultJson} — emits the same JSON shape the review prompt templates
|
|
165
|
+
* instruct (and the schemas enforce), so a prior result can be replayed as an assistant turn in a
|
|
166
|
+
* follow-up conversation without contradicting the format the model is being asked to produce. */
|
|
162
167
|
export function serializeReviewResult(result: AIReviewResult): string {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
const json: ReviewResultJson = {
|
|
169
|
+
overview: result.overview,
|
|
170
|
+
focusAreas: result.focusAreas.map(area => ({
|
|
171
|
+
label: area.label,
|
|
172
|
+
rationale: area.rationale,
|
|
173
|
+
severity: area.severity,
|
|
174
|
+
files: [...area.files],
|
|
175
|
+
findings: area.findings?.map(serializeFindingJson) ?? null,
|
|
176
|
+
})),
|
|
177
|
+
};
|
|
172
178
|
|
|
173
|
-
return
|
|
179
|
+
return JSON.stringify(json, undefined, 2);
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
export function parseReviewDetailResult(result: string, focusAreaId: string): AIReviewDetailResult {
|
|
@@ -181,3 +187,221 @@ export function parseReviewDetailResult(result: string, focusAreaId: string): AI
|
|
|
181
187
|
|
|
182
188
|
return { findings: findings };
|
|
183
189
|
}
|
|
190
|
+
|
|
191
|
+
interface ReviewFindingJson {
|
|
192
|
+
severity?: string;
|
|
193
|
+
title?: string;
|
|
194
|
+
description?: string;
|
|
195
|
+
file?: string | null;
|
|
196
|
+
lines?: { start?: number; end?: number } | null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
interface ReviewResultJson {
|
|
200
|
+
overview?: string;
|
|
201
|
+
focusAreas?:
|
|
202
|
+
| {
|
|
203
|
+
label?: string;
|
|
204
|
+
rationale?: string;
|
|
205
|
+
severity?: string;
|
|
206
|
+
files?: (string | null)[] | null;
|
|
207
|
+
findings?: ReviewFindingJson[] | null;
|
|
208
|
+
}[]
|
|
209
|
+
| null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const fencedJsonBlockRegex = /```(?:json)?\s*([\s\S]*?)\s*```/;
|
|
213
|
+
|
|
214
|
+
/** Returns the contents of the first fenced code block, or the trimmed input when unfenced */
|
|
215
|
+
export function stripJsonCodeFence(text: string): string {
|
|
216
|
+
const fenced = fencedJsonBlockRegex.exec(text);
|
|
217
|
+
return (fenced?.[1] ?? text).trim();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Extracts the first JSON object from the text — tolerating code fences and surrounding prose,
|
|
222
|
+
* since providers without native schema enforcement often wrap the object in explanatory text.
|
|
223
|
+
* Pass `isExpectedShape` so prose braces and stray JSON fragments (including complete nested
|
|
224
|
+
* objects inside truncated output) can't be mistaken for the payload.
|
|
225
|
+
*/
|
|
226
|
+
export function extractJsonObject(
|
|
227
|
+
text: string,
|
|
228
|
+
isExpectedShape?: (parsed: Record<string, unknown>) => boolean,
|
|
229
|
+
): Record<string, unknown> | undefined {
|
|
230
|
+
text = text.trim();
|
|
231
|
+
|
|
232
|
+
let parsed = tryParseObject(text, isExpectedShape);
|
|
233
|
+
if (parsed != null) return parsed;
|
|
234
|
+
|
|
235
|
+
parsed = tryParseObject(stripJsonCodeFence(text), isExpectedShape);
|
|
236
|
+
if (parsed != null) return parsed;
|
|
237
|
+
|
|
238
|
+
// Fall back to balanced objects embedded in surrounding prose, trying each candidate start —
|
|
239
|
+
// prose braces may be unbalanced (`render() {`) or parse to a different shape than expected
|
|
240
|
+
let index = text.indexOf('{');
|
|
241
|
+
while (index !== -1) {
|
|
242
|
+
const balanced = extractBalancedObject(text, index);
|
|
243
|
+
if (balanced != null) {
|
|
244
|
+
parsed = tryParseObject(balanced, isExpectedShape);
|
|
245
|
+
if (parsed != null) return parsed;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
index = text.indexOf('{', index + 1);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function tryParseObject(
|
|
255
|
+
text: string,
|
|
256
|
+
isExpectedShape?: (parsed: Record<string, unknown>) => boolean,
|
|
257
|
+
): Record<string, unknown> | undefined {
|
|
258
|
+
if (!text.startsWith('{')) return undefined;
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
const parsed: unknown = JSON.parse(text);
|
|
262
|
+
if (typeof parsed !== 'object' || parsed == null || Array.isArray(parsed)) return undefined;
|
|
263
|
+
|
|
264
|
+
const obj = parsed as Record<string, unknown>;
|
|
265
|
+
return isExpectedShape == null || isExpectedShape(obj) ? obj : undefined;
|
|
266
|
+
} catch {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function extractBalancedObject(text: string, start: number): string | undefined {
|
|
272
|
+
let depth = 0;
|
|
273
|
+
let inString = false;
|
|
274
|
+
let escaped = false;
|
|
275
|
+
|
|
276
|
+
for (let i = start; i < text.length; i++) {
|
|
277
|
+
const ch = text[i];
|
|
278
|
+
if (escaped) {
|
|
279
|
+
escaped = false;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (inString) {
|
|
284
|
+
if (ch === '\\') {
|
|
285
|
+
escaped = true;
|
|
286
|
+
} else if (ch === '"') {
|
|
287
|
+
inString = false;
|
|
288
|
+
}
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (ch === '"') {
|
|
293
|
+
inString = true;
|
|
294
|
+
} else if (ch === '{') {
|
|
295
|
+
depth++;
|
|
296
|
+
} else if (ch === '}') {
|
|
297
|
+
depth--;
|
|
298
|
+
if (depth === 0) return text.substring(start, i + 1);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Guards schema-typed string fields against non-string values from prompt-only providers */
|
|
306
|
+
function trimmedString(value: unknown): string | undefined {
|
|
307
|
+
return typeof value === 'string' ? value.trim() : undefined;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Line numbers are integers per the schema, but prompt-only providers can emit numeric strings */
|
|
311
|
+
function coerceLineNumber(value: unknown): number | undefined {
|
|
312
|
+
if (typeof value === 'number') return value;
|
|
313
|
+
if (typeof value === 'string') return parseInt(value, 10);
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Normalizes schema null-unions (null → undefined) and synthesizes the same 1-based positional ids
|
|
318
|
+
// as the XML parsers, so ids stay stable regardless of which parse route handled the response
|
|
319
|
+
function normalizeFindingJson(finding: ReviewFindingJson, id: string): AIReviewFinding {
|
|
320
|
+
return {
|
|
321
|
+
id: id,
|
|
322
|
+
severity: parseSeverity(trimmedString(finding.severity)),
|
|
323
|
+
title: trimmedString(finding.title) || 'Untitled finding',
|
|
324
|
+
description: trimmedString(finding.description) ?? '',
|
|
325
|
+
filePath: trimmedString(finding.file) || undefined,
|
|
326
|
+
lineRange: normalizeLineRange(coerceLineNumber(finding.lines?.start), coerceLineNumber(finding.lines?.end)),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Parses a review result, preferring the JSON shape and falling back to the legacy XML format */
|
|
331
|
+
export function parseReviewResultJson(result: string, mode: 'single-pass' | 'two-pass'): AIReviewResult {
|
|
332
|
+
// An empty response is never a valid review — don't render it as a clean "no issues" result
|
|
333
|
+
if (!result.trim()) throw new Error('The AI model returned an empty response');
|
|
334
|
+
|
|
335
|
+
const parsed = extractJsonObject(result, o => typeof o.overview === 'string' || Array.isArray(o.focusAreas)) as
|
|
336
|
+
| ReviewResultJson
|
|
337
|
+
| undefined;
|
|
338
|
+
const overview = typeof parsed?.overview === 'string' ? parsed.overview.trim() : undefined;
|
|
339
|
+
const areas = Array.isArray(parsed?.focusAreas) ? parsed.focusAreas : undefined;
|
|
340
|
+
|
|
341
|
+
if (overview == null && areas == null) {
|
|
342
|
+
const fallback = parseReviewResult(result, mode);
|
|
343
|
+
// A non-empty response matching neither shape is malformed (e.g. truncated JSON) — surface
|
|
344
|
+
// that rather than rendering it as a clean "no issues" review
|
|
345
|
+
if (!fallback.overview && fallback.focusAreas.length === 0 && !result.includes('<overview')) {
|
|
346
|
+
throw new Error('Unable to parse the review response from the AI model');
|
|
347
|
+
}
|
|
348
|
+
return fallback;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const focusAreas: AIReviewFocusArea[] = [];
|
|
352
|
+
let areaIndex = 0;
|
|
353
|
+
|
|
354
|
+
for (const area of areas ?? []) {
|
|
355
|
+
if (area == null || typeof area !== 'object') continue;
|
|
356
|
+
|
|
357
|
+
areaIndex++;
|
|
358
|
+
// Finding ids MUST stay namespaced by area id — dismissed findings are tracked in one flat
|
|
359
|
+
// set spanning all areas, so bare per-area indices would collide across areas
|
|
360
|
+
const id = `area-${areaIndex}`;
|
|
361
|
+
|
|
362
|
+
const findings = Array.isArray(area.findings)
|
|
363
|
+
? area.findings.filter((f): f is ReviewFindingJson => f != null && typeof f === 'object')
|
|
364
|
+
: undefined;
|
|
365
|
+
|
|
366
|
+
focusAreas.push({
|
|
367
|
+
id: id,
|
|
368
|
+
label: trimmedString(area.label) || 'Untitled area',
|
|
369
|
+
rationale: trimmedString(area.rationale) ?? '',
|
|
370
|
+
severity: parseSeverity(trimmedString(area.severity)),
|
|
371
|
+
files: Array.isArray(area.files)
|
|
372
|
+
? area.files.map(f => trimmedString(f)).filter((f): f is string => Boolean(f))
|
|
373
|
+
: [],
|
|
374
|
+
findings: findings?.map((f, i) => normalizeFindingJson(f, `${id}-f${i + 1}`)),
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return { overview: overview ?? '', focusAreas: focusAreas, mode: mode };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Parses a review detail result, preferring the JSON shape and falling back to the legacy XML format */
|
|
382
|
+
export function parseReviewDetailResultJson(result: string, focusAreaId: string): AIReviewDetailResult {
|
|
383
|
+
// An empty response is never a valid result — don't render it as "no findings"
|
|
384
|
+
if (!result.trim()) throw new Error('The AI model returned an empty response');
|
|
385
|
+
|
|
386
|
+
const parsed = extractJsonObject(result, o => o.findings === null || Array.isArray(o.findings)) as
|
|
387
|
+
| { findings?: ReviewFindingJson[] | null }
|
|
388
|
+
| undefined;
|
|
389
|
+
// Tolerate the sibling result schema's null-union — a null `findings` means "no findings"
|
|
390
|
+
if (parsed?.findings === null) return { findings: [] };
|
|
391
|
+
|
|
392
|
+
if (parsed == null || !Array.isArray(parsed.findings)) {
|
|
393
|
+
const fallback = parseReviewDetailResult(result, focusAreaId);
|
|
394
|
+
// Same malformed-response guard as parseReviewResultJson above; an empty legacy
|
|
395
|
+
// `<findings>` block is a legitimate "no findings" response, not a parse failure
|
|
396
|
+
if (fallback.findings.length === 0 && !result.includes('<findings')) {
|
|
397
|
+
throw new Error('Unable to parse the review response from the AI model');
|
|
398
|
+
}
|
|
399
|
+
return fallback;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
findings: parsed.findings
|
|
404
|
+
.filter((f): f is ReviewFindingJson => f != null && typeof f === 'object')
|
|
405
|
+
.map((f, i) => normalizeFindingJson(f, `${focusAreaId}-f${i + 1}`)),
|
|
406
|
+
};
|
|
407
|
+
}
|