@gitkraken/core-gitlens 0.2.0 → 0.3.1
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 +11 -1
- package/dist/git/cache.d.ts +38 -8
- package/dist/git/cache.d.ts.map +1 -1
- package/dist/git/cache.js +120 -55
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +19 -0
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.d.ts.map +1 -1
- package/dist/git/features.js +1 -0
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/commit.d.ts.map +1 -1
- package/dist/git/models/commit.js.map +1 -1
- package/dist/git/models/graph.d.ts +96 -0
- package/dist/git/models/graph.d.ts.map +1 -1
- package/dist/git/models/graph.js +24 -1
- package/dist/git/models/graph.js.map +1 -1
- package/dist/git/models/reference.d.ts +31 -0
- package/dist/git/models/reference.d.ts.map +1 -1
- package/dist/git/models/remote.d.ts.map +1 -1
- package/dist/git/models/remote.js.map +1 -1
- package/dist/git/models/remoteProvider.d.ts +1 -0
- package/dist/git/models/remoteProvider.d.ts.map +1 -1
- package/dist/git/models/remoteProvider.js.map +1 -1
- package/dist/git/models/repository.d.ts +30 -13
- package/dist/git/models/repository.d.ts.map +1 -1
- package/dist/git/models/repository.js +89 -87
- package/dist/git/models/repository.js.map +1 -1
- package/dist/git/models/search.d.ts +2 -2
- package/dist/git/models/search.d.ts.map +1 -1
- package/dist/git/models/statusFile.d.ts +9 -0
- package/dist/git/models/statusFile.d.ts.map +1 -1
- package/dist/git/models/statusFile.js +11 -0
- package/dist/git/models/statusFile.js.map +1 -1
- package/dist/git/models/worktree.d.ts +4 -1
- package/dist/git/models/worktree.d.ts.map +1 -1
- package/dist/git/models/worktree.js +2 -2
- package/dist/git/models/worktree.js.map +1 -1
- package/dist/git/parsers/diffParser.d.ts.map +1 -1
- package/dist/git/parsers/diffParser.js.map +1 -1
- package/dist/git/providers/branches.d.ts +15 -4
- package/dist/git/providers/branches.d.ts.map +1 -1
- package/dist/git/providers/commits.d.ts +4 -0
- package/dist/git/providers/commits.d.ts.map +1 -1
- package/dist/git/providers/config.d.ts +5 -4
- package/dist/git/providers/config.d.ts.map +1 -1
- package/dist/git/providers/operations.d.ts +61 -12
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/pausedOperations.d.ts +3 -1
- package/dist/git/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git/providers/refs.d.ts +23 -2
- package/dist/git/providers/refs.d.ts.map +1 -1
- package/dist/git/providers/staging.d.ts +16 -0
- package/dist/git/providers/staging.d.ts.map +1 -1
- package/dist/git/providers/status.d.ts +4 -1
- package/dist/git/providers/status.d.ts.map +1 -1
- package/dist/git/remotes/azure-devops.d.ts.map +1 -1
- package/dist/git/remotes/azure-devops.js.map +1 -1
- package/dist/git/remotes/custom.d.ts +2 -0
- package/dist/git/remotes/custom.d.ts.map +1 -1
- package/dist/git/remotes/custom.js +20 -0
- package/dist/git/remotes/custom.js.map +1 -1
- package/dist/git/{exec.types.d.ts → run.types.d.ts} +22 -3
- package/dist/git/run.types.d.ts.map +1 -0
- package/dist/git/run.types.js +2 -0
- package/dist/git/run.types.js.map +1 -0
- package/dist/git/service.d.ts.map +1 -1
- package/dist/git/service.js.map +1 -1
- package/dist/git/utils/autolink.utils.d.ts.map +1 -1
- package/dist/git/utils/autolink.utils.js.map +1 -1
- package/dist/git/utils/blame.utils.d.ts.map +1 -1
- package/dist/git/utils/blame.utils.js.map +1 -1
- package/dist/git/utils/conflictResolution.utils.d.ts +6 -0
- package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -0
- package/dist/git/utils/conflictResolution.utils.js +25 -0
- package/dist/git/utils/conflictResolution.utils.js.map +1 -0
- package/dist/git/utils/contributor.utils.d.ts +3 -0
- package/dist/git/utils/contributor.utils.d.ts.map +1 -1
- package/dist/git/utils/contributor.utils.js +22 -0
- package/dist/git/utils/contributor.utils.js.map +1 -1
- package/dist/git/utils/fileStatus.utils.d.ts +2 -1
- package/dist/git/utils/fileStatus.utils.d.ts.map +1 -1
- package/dist/git/utils/fileStatus.utils.js +4 -0
- package/dist/git/utils/fileStatus.utils.js.map +1 -1
- package/dist/git/utils/reachability.utils.d.ts +37 -0
- package/dist/git/utils/reachability.utils.d.ts.map +1 -0
- package/dist/git/utils/reachability.utils.js +96 -0
- package/dist/git/utils/reachability.utils.js.map +1 -0
- package/dist/git/utils/search.utils.d.ts.map +1 -1
- package/dist/git/utils/search.utils.js +3 -0
- package/dist/git/utils/search.utils.js.map +1 -1
- package/dist/git/utils/sorting.d.ts +8 -0
- package/dist/git/utils/sorting.d.ts.map +1 -1
- package/dist/git/utils/sorting.js +15 -0
- package/dist/git/utils/sorting.js.map +1 -1
- package/dist/git/utils/status.utils.d.ts.map +1 -1
- package/dist/git/utils/status.utils.js.map +1 -1
- package/dist/git/watching/classifyChange.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.js +8 -0
- package/dist/git/watching/classifyChange.js.map +1 -1
- package/dist/git/watching/gitIgnoreFilter.js +1 -1
- package/dist/git/watching/gitIgnoreFilter.js.map +1 -1
- package/dist/git/watching/initWatcher.d.ts.map +1 -1
- package/dist/git/watching/initWatcher.js.map +1 -1
- package/dist/git/watching/watchGroup.d.ts.map +1 -1
- package/dist/git/watching/watchGroup.js.map +1 -1
- package/dist/git/watching/watchService.d.ts +4 -2
- package/dist/git/watching/watchService.d.ts.map +1 -1
- package/dist/git/watching/watchService.js +31 -6
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +14 -12
- package/dist/git/watching/watchSession.d.ts.map +1 -1
- package/dist/git/watching/watchSession.js +56 -55
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git-cli/exec/exec.types.d.ts +1 -1
- package/dist/git-cli/exec/exec.types.d.ts.map +1 -1
- package/dist/git-cli/exec/git.d.ts +3 -3
- package/dist/git-cli/exec/git.d.ts.map +1 -1
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +10 -2
- package/dist/git-cli/exec/gitQueue.d.ts.map +1 -1
- package/dist/git-cli/exec/gitQueue.js +39 -12
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/parsers/blameParser.d.ts.map +1 -1
- package/dist/git-cli/parsers/blameParser.js.map +1 -1
- package/dist/git-cli/parsers/logParser.js.map +1 -1
- package/dist/git-cli/parsers/refParser.d.ts +3 -30
- package/dist/git-cli/parsers/refParser.d.ts.map +1 -1
- package/dist/git-cli/parsers/refParser.js +30 -30
- package/dist/git-cli/parsers/refParser.js.map +1 -1
- package/dist/git-cli/providers/blame.d.ts.map +1 -1
- package/dist/git-cli/providers/blame.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +15 -5
- package/dist/git-cli/providers/branches.d.ts.map +1 -1
- package/dist/git-cli/providers/branches.js +99 -68
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +1 -0
- package/dist/git-cli/providers/commits.d.ts.map +1 -1
- package/dist/git-cli/providers/commits.js +86 -30
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +19 -6
- package/dist/git-cli/providers/config.d.ts.map +1 -1
- package/dist/git-cli/providers/config.js +86 -38
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/diff.d.ts.map +1 -1
- package/dist/git-cli/providers/diff.js +5 -3
- package/dist/git-cli/providers/diff.js.map +1 -1
- package/dist/git-cli/providers/graph.d.ts.map +1 -1
- package/dist/git-cli/providers/graph.js +139 -16
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +17 -14
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +135 -63
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.d.ts.map +1 -1
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
- package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +7 -1
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +19 -2
- package/dist/git-cli/providers/refs.d.ts.map +1 -1
- package/dist/git-cli/providers/refs.js +286 -2
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +6 -0
- package/dist/git-cli/providers/staging.d.ts.map +1 -1
- package/dist/git-cli/providers/staging.js +32 -0
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts.map +1 -1
- package/dist/git-cli/providers/stash.js +20 -2
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +4 -1
- package/dist/git-cli/providers/status.d.ts.map +1 -1
- package/dist/git-cli/providers/status.js +8 -4
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/tags.d.ts.map +1 -1
- package/dist/git-cli/providers/tags.js +10 -6
- package/dist/git-cli/providers/tags.js.map +1 -1
- package/dist/ipc/discovery.d.ts +49 -0
- package/dist/ipc/discovery.d.ts.map +1 -0
- package/dist/ipc/discovery.js +147 -0
- package/dist/ipc/discovery.js.map +1 -0
- package/dist/ipc/ipcServer.d.ts +20 -0
- package/dist/ipc/ipcServer.d.ts.map +1 -0
- package/dist/ipc/ipcServer.js +162 -0
- package/dist/ipc/ipcServer.js.map +1 -0
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts +167 -0
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -0
- package/dist/plus/agents/providers/claudeCodeProvider.js +1786 -0
- package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -0
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +36 -0
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -0
- package/dist/plus/agents/providers/claudeCodeTranscript.js +171 -0
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -0
- package/dist/plus/agents/sanitizePrompt.d.ts +15 -0
- package/dist/plus/agents/sanitizePrompt.d.ts.map +1 -0
- package/dist/plus/agents/sanitizePrompt.js +103 -0
- package/dist/plus/agents/sanitizePrompt.js.map +1 -0
- package/dist/plus/agents/stateMachine.d.ts +32 -0
- package/dist/plus/agents/stateMachine.d.ts.map +1 -0
- package/dist/plus/agents/stateMachine.js +180 -0
- package/dist/plus/agents/stateMachine.js.map +1 -0
- package/dist/plus/agents/types.d.ts +254 -0
- package/dist/plus/agents/types.d.ts.map +1 -0
- package/dist/plus/agents/types.js +49 -0
- package/dist/plus/agents/types.js.map +1 -0
- package/dist/plus/ai/errors.d.ts +4 -1
- package/dist/plus/ai/errors.d.ts.map +1 -1
- package/dist/plus/ai/errors.js +38 -0
- package/dist/plus/ai/errors.js.map +1 -1
- package/dist/plus/ai/models/model.d.ts +1 -1
- package/dist/plus/ai/models/model.d.ts.map +1 -1
- package/dist/plus/ai/models/model.js.map +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts +11 -2
- package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
- package/dist/plus/ai/models/provider.d.ts +3 -0
- package/dist/plus/ai/models/provider.d.ts.map +1 -1
- package/dist/plus/ai/prompts.d.ts +1 -0
- package/dist/plus/ai/prompts.d.ts.map +1 -1
- package/dist/plus/ai/prompts.js +48 -8
- package/dist/plus/ai/prompts.js.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js +4 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +4 -3
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +9 -6
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +2 -0
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/results.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +12 -1
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +245 -51
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/api/types.d.ts +8 -0
- package/dist/plus/git-github/api/types.d.ts.map +1 -1
- package/dist/plus/git-github/models.d.ts +1 -1
- package/dist/plus/git-github/models.d.ts.map +1 -1
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/git-github/providers/github/blame.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/blame.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts +5 -1
- package/dist/plus/git-github/providers/github/branches.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/branches.js +47 -24
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/git-github/providers/github/commits.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/commits.js +144 -92
- package/dist/plus/git-github/providers/github/commits.js.map +1 -1
- package/dist/plus/git-github/providers/github/diff.d.ts +1 -1
- package/dist/plus/git-github/providers/github/diff.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/diff.js +23 -9
- package/dist/plus/git-github/providers/github/diff.js.map +1 -1
- package/dist/plus/git-github/providers/github/refs.d.ts +9 -1
- package/dist/plus/git-github/providers/github/refs.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/refs.js +39 -14
- package/dist/plus/git-github/providers/github/refs.js.map +1 -1
- package/dist/plus/git-github/providers/github/revision.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/revision.js +1 -2
- package/dist/plus/git-github/providers/github/revision.js.map +1 -1
- package/dist/plus/git-github/providers/github/status.d.ts +4 -1
- package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/status.js +1 -1
- package/dist/plus/git-github/providers/github/status.js.map +1 -1
- package/dist/plus/git-github/providers/github/tags.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/tags.js +35 -36
- package/dist/plus/git-github/providers/github/tags.js.map +1 -1
- package/dist/plus/git-github/providers/githubGitProvider.d.ts.map +1 -1
- package/dist/plus/git-github/providers/githubGitProvider.js.map +1 -1
- package/dist/utils/color.d.ts.map +1 -1
- package/dist/utils/color.js.map +1 -1
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +6 -0
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/debounce.js +1 -1
- package/dist/utils/decorators/serializable.d.ts.map +1 -1
- package/dist/utils/decorators/serializable.js.map +1 -1
- package/dist/utils/dedupedAsyncCache.d.ts +37 -0
- package/dist/utils/dedupedAsyncCache.d.ts.map +1 -0
- package/dist/utils/dedupedAsyncCache.js +68 -0
- package/dist/utils/dedupedAsyncCache.js.map +1 -0
- package/dist/utils/diff.d.ts +2 -0
- package/dist/utils/diff.d.ts.map +1 -0
- package/dist/utils/diff.js +53 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/disposable.d.ts.map +1 -1
- package/dist/utils/disposable.js.map +1 -1
- package/dist/utils/env/node/exec.d.ts.map +1 -1
- package/dist/utils/env/node/exec.js.map +1 -1
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/iterable.d.ts +7 -1
- package/dist/utils/iterable.d.ts.map +1 -1
- package/dist/utils/iterable.js +12 -4
- package/dist/utils/iterable.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/lruMap.d.ts +9 -0
- package/dist/utils/lruMap.d.ts.map +1 -1
- package/dist/utils/lruMap.js +26 -4
- package/dist/utils/lruMap.js.map +1 -1
- package/dist/utils/markdown.d.ts.map +1 -1
- package/dist/utils/markdown.js.map +1 -1
- package/dist/utils/mru.d.ts.map +1 -1
- package/dist/utils/mru.js.map +1 -1
- package/dist/utils/object.d.ts +22 -1
- package/dist/utils/object.d.ts.map +1 -1
- package/dist/utils/object.js +56 -3
- package/dist/utils/object.js.map +1 -1
- package/dist/utils/paging.js +14 -15
- package/dist/utils/paging.js.map +1 -1
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/promise.d.ts +1 -0
- package/dist/utils/promise.d.ts.map +1 -1
- package/dist/utils/promise.js +17 -0
- package/dist/utils/promise.js.map +1 -1
- package/dist/utils/promiseCache.d.ts +10 -0
- package/dist/utils/promiseCache.d.ts.map +1 -1
- package/dist/utils/promiseCache.js +34 -4
- package/dist/utils/promiseCache.js.map +1 -1
- package/dist/utils/string.d.ts.map +1 -1
- package/dist/utils/string.js +1 -1
- package/dist/utils/string.js.map +1 -1
- package/dist/utils/uri.d.ts.map +1 -1
- package/dist/utils/uri.js.map +1 -1
- package/dist/utils/version.d.ts.map +1 -1
- package/dist/utils/version.js.map +1 -1
- package/package.json +13 -1
- package/src/git/cache.ts +192 -90
- package/src/git/context.ts +21 -0
- package/src/git/features.ts +2 -0
- package/src/git/models/commit.ts +1 -0
- package/src/git/models/graph.ts +97 -0
- package/src/git/models/reference.ts +33 -0
- package/src/git/models/remote.ts +1 -0
- package/src/git/models/remoteProvider.ts +1 -0
- package/src/git/models/repository.ts +105 -96
- package/src/git/models/search.ts +2 -2
- package/src/git/models/statusFile.ts +12 -0
- package/src/git/models/worktree.ts +10 -2
- package/src/git/parsers/diffParser.ts +2 -0
- package/src/git/providers/branches.ts +22 -4
- package/src/git/providers/commits.ts +4 -0
- package/src/git/providers/config.ts +3 -5
- package/src/git/providers/operations.ts +65 -1
- package/src/git/providers/pausedOperations.ts +1 -0
- package/src/git/providers/refs.ts +32 -3
- package/src/git/providers/staging.ts +12 -0
- package/src/git/providers/status.ts +6 -1
- package/src/git/remotes/azure-devops.ts +2 -0
- package/src/git/remotes/custom.ts +23 -0
- package/src/git/{exec.types.ts → run.types.ts} +22 -2
- package/src/git/service.ts +1 -0
- package/src/git/utils/autolink.utils.ts +1 -0
- package/src/git/utils/blame.utils.ts +2 -0
- package/src/git/utils/conflictResolution.utils.ts +31 -0
- package/src/git/utils/contributor.utils.ts +24 -0
- package/src/git/utils/fileStatus.utils.ts +7 -1
- package/src/git/utils/reachability.utils.ts +109 -0
- package/src/git/utils/search.utils.ts +2 -0
- package/src/git/utils/sorting.ts +17 -0
- package/src/git/utils/status.utils.ts +1 -0
- package/src/git/watching/classifyChange.ts +9 -0
- package/src/git/watching/gitIgnoreFilter.ts +2 -2
- package/src/git/watching/initWatcher.ts +2 -0
- package/src/git/watching/watchGroup.ts +3 -0
- package/src/git/watching/watchService.ts +45 -7
- package/src/git/watching/watchSession.ts +71 -55
- package/src/git-cli/exec/exec.types.ts +2 -2
- package/src/git-cli/exec/git.ts +6 -5
- package/src/git-cli/exec/gitQueue.ts +41 -12
- package/src/git-cli/parsers/blameParser.ts +1 -0
- package/src/git-cli/parsers/logParser.ts +1 -0
- package/src/git-cli/parsers/refParser.ts +33 -34
- package/src/git-cli/providers/blame.ts +1 -0
- package/src/git-cli/providers/branches.ts +165 -93
- package/src/git-cli/providers/commits.ts +107 -37
- package/src/git-cli/providers/config.ts +101 -48
- package/src/git-cli/providers/diff.ts +10 -3
- package/src/git-cli/providers/graph.ts +156 -16
- package/src/git-cli/providers/operations.ts +208 -83
- package/src/git-cli/providers/patch.ts +1 -0
- package/src/git-cli/providers/pausedOperations.ts +8 -0
- package/src/git-cli/providers/refs.ts +247 -3
- package/src/git-cli/providers/revision.ts +2 -2
- package/src/git-cli/providers/staging.ts +33 -0
- package/src/git-cli/providers/stash.ts +20 -2
- package/src/git-cli/providers/status.ts +24 -5
- package/src/git-cli/providers/tags.ts +15 -16
- package/src/ipc/discovery.ts +186 -0
- package/src/ipc/ipcServer.ts +171 -0
- package/src/plus/agents/providers/claudeCodeProvider.ts +2122 -0
- package/src/plus/agents/providers/claudeCodeTranscript.ts +214 -0
- package/src/plus/agents/sanitizePrompt.ts +109 -0
- package/src/plus/agents/stateMachine.ts +197 -0
- package/src/plus/agents/types.ts +325 -0
- package/src/plus/ai/errors.ts +40 -0
- package/src/plus/ai/models/model.ts +1 -0
- package/src/plus/ai/models/promptTemplates.ts +13 -0
- package/src/plus/ai/models/provider.ts +7 -1
- package/src/plus/ai/prompts.ts +49 -8
- package/src/plus/ai/providers/gitkrakenProvider.ts +4 -0
- package/src/plus/ai/providers/openAICompatibleProviderBase.ts +21 -4
- package/src/plus/ai/utils/ai.utils.ts +2 -0
- package/src/plus/ai/utils/results.utils.ts +2 -0
- package/src/plus/git-github/api/github.ts +315 -57
- package/src/plus/git-github/api/types.ts +15 -0
- package/src/plus/git-github/models.ts +1 -1
- package/src/plus/git-github/providers/github/blame.ts +2 -0
- package/src/plus/git-github/providers/github/branches.ts +61 -31
- package/src/plus/git-github/providers/github/commits.ts +231 -160
- package/src/plus/git-github/providers/github/diff.ts +27 -19
- package/src/plus/git-github/providers/github/refs.ts +58 -23
- package/src/plus/git-github/providers/github/revision.ts +1 -2
- package/src/plus/git-github/providers/github/status.ts +6 -1
- package/src/plus/git-github/providers/github/tags.ts +61 -62
- package/src/plus/git-github/providers/githubGitProvider.ts +1 -0
- package/src/utils/color.ts +2 -0
- package/src/utils/date.ts +5 -0
- package/src/utils/debounce.ts +1 -1
- package/src/utils/decorators/serializable.ts +1 -0
- package/src/utils/dedupedAsyncCache.ts +74 -0
- package/src/utils/diff.ts +61 -0
- package/src/utils/disposable.ts +2 -0
- package/src/utils/env/node/exec.ts +2 -0
- package/src/utils/error.ts +1 -0
- package/src/utils/iterable.ts +17 -3
- package/src/utils/logger.ts +1 -0
- package/src/utils/lruMap.ts +29 -4
- package/src/utils/markdown.ts +1 -0
- package/src/utils/mru.ts +2 -0
- package/src/utils/object.ts +55 -4
- package/src/utils/paging.ts +14 -14
- package/src/utils/path.ts +1 -0
- package/src/utils/promise.ts +22 -0
- package/src/utils/promiseCache.ts +48 -16
- package/src/utils/string.ts +3 -1
- package/src/utils/uri.ts +1 -0
- package/src/utils/version.ts +1 -0
- package/dist/git/exec.types.d.ts.map +0 -1
- package/dist/git/exec.types.js +0 -2
- package/dist/git/exec.types.js.map +0 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { createReadStream } from 'fs';
|
|
2
|
+
import { readdir, stat } from 'fs/promises';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
export interface TranscriptTitles {
|
|
7
|
+
custom?: string;
|
|
8
|
+
ai?: string;
|
|
9
|
+
agent?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface CacheEntry {
|
|
13
|
+
path: string;
|
|
14
|
+
mtimeMs: number;
|
|
15
|
+
size: number;
|
|
16
|
+
nextOffset: number;
|
|
17
|
+
titles: TranscriptTitles;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface TitleEntry {
|
|
21
|
+
type: string;
|
|
22
|
+
sessionId?: string;
|
|
23
|
+
customTitle?: string;
|
|
24
|
+
aiTitle?: string;
|
|
25
|
+
agentName?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reads Claude Code transcript JSONL files at `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`
|
|
30
|
+
* to surface `custom-title`, `ai-title`, and `agent-name` entries as fallback session names.
|
|
31
|
+
*
|
|
32
|
+
* Maintains a per-session cache keyed by mtime + last-read byte offset, so repeated calls only
|
|
33
|
+
* read the appended tail. Last occurrence per type wins.
|
|
34
|
+
*
|
|
35
|
+
* `resolve` is async, so a `forget` (or a newer `resolve`) for the same session can land between
|
|
36
|
+
* its `await`s. A per-session generation counter is stamped at entry and re-checked before the
|
|
37
|
+
* final cache write, so a stale `resolve` can't resurrect a forgotten entry or clobber a newer
|
|
38
|
+
* resolve's result.
|
|
39
|
+
*/
|
|
40
|
+
export class ClaudeCodeTranscriptReader {
|
|
41
|
+
private readonly _cache = new Map<string, CacheEntry>();
|
|
42
|
+
private readonly _generations = new Map<string, number>();
|
|
43
|
+
private _nextGen = 0;
|
|
44
|
+
|
|
45
|
+
async resolve(sessionId: string, cwd: string | undefined): Promise<TranscriptTitles | undefined> {
|
|
46
|
+
const gen = ++this._nextGen;
|
|
47
|
+
this._generations.set(sessionId, gen);
|
|
48
|
+
|
|
49
|
+
const cached = this._cache.get(sessionId);
|
|
50
|
+
const path = cached?.path ?? (await this.locateTranscript(sessionId, cwd));
|
|
51
|
+
if (path == null) return undefined;
|
|
52
|
+
|
|
53
|
+
let stats;
|
|
54
|
+
try {
|
|
55
|
+
stats = await stat(path);
|
|
56
|
+
} catch {
|
|
57
|
+
// File disappeared; drop any stale cache entry so a future call retries discovery.
|
|
58
|
+
// Skip the delete if a newer resolve/forget claimed the slot — their state is fresher.
|
|
59
|
+
if (this._generations.get(sessionId) === gen) {
|
|
60
|
+
this._cache.delete(sessionId);
|
|
61
|
+
this._generations.delete(sessionId);
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (stats.mtimeMs === cached?.mtimeMs && stats.size === cached?.size) {
|
|
67
|
+
return cached.titles;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Truncation or rewrite: stat shrank below our read cursor or mtime moved backward → full re-scan.
|
|
71
|
+
const startFromScratch = cached == null || stats.size < cached.nextOffset || stats.mtimeMs < cached.mtimeMs;
|
|
72
|
+
const startOffset = startFromScratch ? 0 : cached.nextOffset;
|
|
73
|
+
const baseTitles: TranscriptTitles = startFromScratch ? {} : { ...cached.titles };
|
|
74
|
+
|
|
75
|
+
const { titles, consumedEnd } =
|
|
76
|
+
stats.size > startOffset
|
|
77
|
+
? await this.readRange(path, startOffset, stats.size, sessionId, baseTitles)
|
|
78
|
+
: { titles: baseTitles, consumedEnd: startOffset };
|
|
79
|
+
|
|
80
|
+
// If `forget` ran or a newer `resolve` started while we were awaiting, skip the cache write
|
|
81
|
+
// — the entry we'd be writing reflects stale state.
|
|
82
|
+
if (this._generations.get(sessionId) !== gen) return titles;
|
|
83
|
+
|
|
84
|
+
const entry: CacheEntry = {
|
|
85
|
+
path: path,
|
|
86
|
+
mtimeMs: stats.mtimeMs,
|
|
87
|
+
size: stats.size,
|
|
88
|
+
nextOffset: consumedEnd,
|
|
89
|
+
titles: titles,
|
|
90
|
+
};
|
|
91
|
+
this._cache.set(sessionId, entry);
|
|
92
|
+
return titles;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
forget(sessionId: string): void {
|
|
96
|
+
this._cache.delete(sessionId);
|
|
97
|
+
this._generations.delete(sessionId);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected async locateTranscript(sessionId: string, cwd: string | undefined): Promise<string | undefined> {
|
|
101
|
+
const root = join(homedir(), '.claude', 'projects');
|
|
102
|
+
const fileName = `${sessionId}.jsonl`;
|
|
103
|
+
|
|
104
|
+
if (cwd != null && cwd.length > 0) {
|
|
105
|
+
const encoded = cwd.replace(/[/\\:]/g, '-');
|
|
106
|
+
const candidate = join(root, encoded, fileName);
|
|
107
|
+
if (await fileExists(candidate)) return candidate;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let dirs: string[];
|
|
111
|
+
try {
|
|
112
|
+
dirs = await readdir(root);
|
|
113
|
+
} catch {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const candidates = await Promise.all(
|
|
118
|
+
dirs.map(async dir => {
|
|
119
|
+
const candidate = join(root, dir, fileName);
|
|
120
|
+
return (await fileExists(candidate)) ? candidate : undefined;
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
return candidates.find(c => c != null);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Reads bytes `[start, end)` from `path` and applies any title entries it finds to a copy of
|
|
128
|
+
* `baseTitles`. Returns the merged titles and the byte position immediately after the last
|
|
129
|
+
* newline observed — partial trailing lines (writer hasn't flushed `\n` yet) are intentionally
|
|
130
|
+
* left unconsumed so they're re-read on the next pass.
|
|
131
|
+
*/
|
|
132
|
+
protected async readRange(
|
|
133
|
+
path: string,
|
|
134
|
+
start: number,
|
|
135
|
+
end: number,
|
|
136
|
+
sessionId: string,
|
|
137
|
+
baseTitles: TranscriptTitles,
|
|
138
|
+
): Promise<{ titles: TranscriptTitles; consumedEnd: number }> {
|
|
139
|
+
const buffer = await readSlice(path, start, end);
|
|
140
|
+
const titles: TranscriptTitles = { ...baseTitles };
|
|
141
|
+
|
|
142
|
+
let lastNewlineEnd = start;
|
|
143
|
+
let lineStart = 0;
|
|
144
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
145
|
+
if (buffer[i] !== 0x0a) continue;
|
|
146
|
+
|
|
147
|
+
// Slice the line (trim a trailing \r for CRLF files), then advance the cursor past the \n
|
|
148
|
+
// regardless of whether the line yielded anything — we've fully observed those bytes.
|
|
149
|
+
const lineEnd = i > lineStart && buffer[i - 1] === 0x0d ? i - 1 : i;
|
|
150
|
+
if (lineEnd > lineStart) {
|
|
151
|
+
const line = buffer.toString('utf8', lineStart, lineEnd);
|
|
152
|
+
applyTitleLine(line, sessionId, titles);
|
|
153
|
+
}
|
|
154
|
+
lineStart = i + 1;
|
|
155
|
+
lastNewlineEnd = start + i + 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { titles: titles, consumedEnd: lastNewlineEnd };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function applyTitleLine(line: string, sessionId: string, titles: TranscriptTitles): void {
|
|
163
|
+
if (!isLikelyTitleLine(line)) return;
|
|
164
|
+
|
|
165
|
+
let entry: TitleEntry;
|
|
166
|
+
try {
|
|
167
|
+
entry = JSON.parse(line) as TitleEntry;
|
|
168
|
+
} catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (entry.sessionId != null && entry.sessionId !== sessionId) return;
|
|
172
|
+
|
|
173
|
+
switch (entry.type) {
|
|
174
|
+
case 'custom-title':
|
|
175
|
+
if (typeof entry.customTitle === 'string' && entry.customTitle.length > 0) {
|
|
176
|
+
titles.custom = entry.customTitle;
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
case 'ai-title':
|
|
180
|
+
if (typeof entry.aiTitle === 'string' && entry.aiTitle.length > 0) {
|
|
181
|
+
titles.ai = entry.aiTitle;
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
case 'agent-name':
|
|
185
|
+
if (typeof entry.agentName === 'string' && entry.agentName.length > 0) {
|
|
186
|
+
titles.agent = entry.agentName;
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function isLikelyTitleLine(line: string): boolean {
|
|
193
|
+
if (!line.includes('"type"')) return false;
|
|
194
|
+
return line.includes('-title') || line.includes('agent-name');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function fileExists(path: string): Promise<boolean> {
|
|
198
|
+
try {
|
|
199
|
+
const stats = await stat(path);
|
|
200
|
+
return stats.isFile();
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function readSlice(path: string, start: number, end: number): Promise<Buffer> {
|
|
207
|
+
return new Promise((resolve, reject) => {
|
|
208
|
+
const chunks: Buffer[] = [];
|
|
209
|
+
const stream = createReadStream(path, { start: start, end: end - 1 });
|
|
210
|
+
stream.on('data', chunk => chunks.push(chunk as Buffer));
|
|
211
|
+
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
|
212
|
+
stream.on('error', reject);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { truncate } from '../../utils/string.js';
|
|
2
|
+
|
|
3
|
+
const maxStoredPromptLength = 500;
|
|
4
|
+
|
|
5
|
+
// Marker blocks GitLens itself embeds when dispatching Start Work / Start Review prompts to an
|
|
6
|
+
// agent (see `start-work-issue` / `start-review-pullRequest` templates in
|
|
7
|
+
// `packages/plus/ai/src/prompts.ts`). The surrounding template begins with a long
|
|
8
|
+
// "You are an advanced AI programming assistant…" preamble that would otherwise become the
|
|
9
|
+
// session's display name; matching on the block delimiters lets us pull the issue/PR title out
|
|
10
|
+
// of the embedded JSON instead.
|
|
11
|
+
const dispatchBlockRegex = /<(issue|prData)>([\s\S]*?)<\/\1>/;
|
|
12
|
+
|
|
13
|
+
// Wrappers the Claude Code harness or its VS Code extension prepend to the `prompt` field of
|
|
14
|
+
// `UserPromptSubmit` hook events. These are synthetic context blocks, not user-typed content,
|
|
15
|
+
// and shouldn't appear verbatim in GitLens agent status UI.
|
|
16
|
+
const harnessBlockPatterns: readonly RegExp[] = [
|
|
17
|
+
// VS Code extension: any current or future IDE-context tag (e.g. <ide_opened_file>,
|
|
18
|
+
// <ide_selection>). Prefix-matched so newly-added ones are handled automatically.
|
|
19
|
+
/<(ide_[a-zA-Z0-9_]+)(?:\s[^>]*)?>[\s\S]*?<\/\1>/g,
|
|
20
|
+
// VS Code extension: @terminal:<name> mention expansion. Gated on the `name` attribute so we
|
|
21
|
+
// don't strip a bare <terminal> a user pasted as code.
|
|
22
|
+
/<terminal\s+name="[^"]*"[^>]*>[\s\S]*?<\/terminal>/g,
|
|
23
|
+
// VS Code extension: @browser mention expansion. Gated on tabGroupId/tabId for the same reason.
|
|
24
|
+
/<browser\s+[^>]*\b(?:tabGroupId|tabId)="[^"]*"[^>]*>[\s\S]*?<\/browser>/g,
|
|
25
|
+
// VS Code extension: one-shot system instruction prepended whenever any @browser is present.
|
|
26
|
+
/<browser_instruction>[\s\S]*?<\/browser_instruction>/g,
|
|
27
|
+
// CLI harness: background-bash task lifecycle event (status, summary, output-file, etc.).
|
|
28
|
+
/<task-notification>[\s\S]*?<\/task-notification>/g,
|
|
29
|
+
// CLI harness: built-in slash-command stdout/stderr echo and caveat note.
|
|
30
|
+
/<(local-command-(?:stdout|stderr|caveat))>[\s\S]*?<\/\1>/g,
|
|
31
|
+
// CLI harness: bang-prefix bash invocation echo (input/stdout/stderr).
|
|
32
|
+
/<(bash-(?:input|stdout|stderr))>[\s\S]*?<\/\1>/g,
|
|
33
|
+
// CLI harness: tool-permission response wrapper.
|
|
34
|
+
/<permissionresponse>[\s\S]*?<\/permissionresponse>/g,
|
|
35
|
+
// Anthropic shared-context blocks (claude.ai web-app feature; defensive).
|
|
36
|
+
/<shared-context(?:\s[^>]*)?>[\s\S]*?<\/shared-context>/g,
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Normalizes a Claude Code `UserPromptSubmit` event prompt into something fit for display in
|
|
41
|
+
* GitLens (agent status pill, sidebar tooltip, etc.) by stripping harness-injected wrappers.
|
|
42
|
+
*
|
|
43
|
+
* Returns `undefined` for empty input or when the prompt was nothing but harness context, so the
|
|
44
|
+
* caller can skip overwriting the previously-captured user prompt.
|
|
45
|
+
*/
|
|
46
|
+
export function sanitizeAgentPrompt(prompt: string | undefined): string | undefined {
|
|
47
|
+
if (!prompt) return undefined;
|
|
48
|
+
|
|
49
|
+
// Normalize CRLF up-front so the harness-block and whitespace-collapse regexes (which target
|
|
50
|
+
// `\n`) behave identically for Windows-originated prompts.
|
|
51
|
+
let result = prompt.replace(/\r\n/g, '\n');
|
|
52
|
+
|
|
53
|
+
let stripped = false;
|
|
54
|
+
for (const pattern of harnessBlockPatterns) {
|
|
55
|
+
const next = result.replace(pattern, '');
|
|
56
|
+
if (next !== result) {
|
|
57
|
+
stripped = true;
|
|
58
|
+
result = next;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// GitLens-dispatched Start Work / Start Review prompts: replace the template body with just
|
|
63
|
+
// the issue/PR title so the session name doesn't surface the "You are an advanced AI…"
|
|
64
|
+
// preamble. Runs AFTER harness stripping so that an `<ide_selection>` (or other wrapper)
|
|
65
|
+
// containing an `<issue>…</issue>` block doesn't get rewritten to the embedded title — the
|
|
66
|
+
// wrapper is stripped first and only a genuine dispatch template body triggers the rewrite.
|
|
67
|
+
// Anything that doesn't yield a usable title falls through to normal sanitization.
|
|
68
|
+
const dispatchTitle = extractDispatchTitle(result);
|
|
69
|
+
if (dispatchTitle != null) return dispatchTitle;
|
|
70
|
+
|
|
71
|
+
// Only collapse the whitespace runs around stripped blocks. Untouched user prompts pass
|
|
72
|
+
// through with their internal whitespace intact (the final trim still removes the outer
|
|
73
|
+
// padding either way).
|
|
74
|
+
if (stripped) {
|
|
75
|
+
result = result.replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n');
|
|
76
|
+
}
|
|
77
|
+
result = result.trim();
|
|
78
|
+
return result || undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Sanitizes and truncates a raw prompt for storage on an `AgentSession`. Use this everywhere a
|
|
83
|
+
* session's `lastPrompt` / `firstPrompt` is populated so the sanitize+truncate pipeline can't be
|
|
84
|
+
* applied inconsistently across capture paths (hook events, CLI session-state syncs, etc.).
|
|
85
|
+
*/
|
|
86
|
+
export function prepareStoredPrompt(prompt: string | undefined): string | undefined {
|
|
87
|
+
const cleaned = sanitizeAgentPrompt(prompt);
|
|
88
|
+
return cleaned ? truncate(cleaned, maxStoredPromptLength) : undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Looks for a GitLens-dispatch marker block (`<issue>…</issue>` or `<prData>…</prData>`) and
|
|
93
|
+
* returns the embedded `title` field. Both `IssueShape` and `PullRequestShape` carry `title`, so
|
|
94
|
+
* a single accessor covers Start Work and Start Review. Returns `undefined` when the block is
|
|
95
|
+
* absent, the JSON fails to parse, or `title` is missing/empty — those cases fall through to the
|
|
96
|
+
* regular sanitization path.
|
|
97
|
+
*/
|
|
98
|
+
function extractDispatchTitle(prompt: string): string | undefined {
|
|
99
|
+
const match = dispatchBlockRegex.exec(prompt);
|
|
100
|
+
if (match == null) return undefined;
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(match[2]) as { title?: unknown };
|
|
104
|
+
const title = typeof parsed.title === 'string' ? parsed.title.trim() : '';
|
|
105
|
+
return title.length > 0 ? title : undefined;
|
|
106
|
+
} catch {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { kill } from 'process';
|
|
2
|
+
import type { AgentSession, AgentSessionStatus, PendingPermissionKind } from './types.js';
|
|
3
|
+
|
|
4
|
+
/** Cap for derived plan / question summaries — short enough to clamp into a card row without
|
|
5
|
+
* truncation eating the leading content, long enough to convey what the prompt is about. */
|
|
6
|
+
const summaryMaxLength = 120;
|
|
7
|
+
|
|
8
|
+
export function deriveStatusFromEvent(event: string): AgentSessionStatus {
|
|
9
|
+
switch (event) {
|
|
10
|
+
case 'SessionStart':
|
|
11
|
+
case 'Stop':
|
|
12
|
+
case 'StopFailure':
|
|
13
|
+
return 'idle';
|
|
14
|
+
case 'PreToolUse':
|
|
15
|
+
return 'tool_use';
|
|
16
|
+
case 'PreCompact':
|
|
17
|
+
return 'compacting';
|
|
18
|
+
case 'PermissionRequest':
|
|
19
|
+
case 'Elicitation':
|
|
20
|
+
return 'permission_requested';
|
|
21
|
+
case 'UserPromptSubmit':
|
|
22
|
+
case 'PostToolUse':
|
|
23
|
+
case 'PostToolUseFailure':
|
|
24
|
+
case 'PostCompact':
|
|
25
|
+
case 'PermissionDenied':
|
|
26
|
+
case 'ElicitationResult':
|
|
27
|
+
case 'SubagentStart':
|
|
28
|
+
case 'SubagentStop':
|
|
29
|
+
return 'thinking';
|
|
30
|
+
default:
|
|
31
|
+
return 'idle';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isProcessAlive(pid: number): boolean {
|
|
36
|
+
// `kill(0, ...)` and `kill(<negative>, ...)` have process-group semantics on POSIX
|
|
37
|
+
// (and target the current process under libuv on Windows), so they don't tell us
|
|
38
|
+
// anything about a specific pid. Reject anything that isn't a real, positive pid.
|
|
39
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
kill(pid, 0);
|
|
43
|
+
return true;
|
|
44
|
+
} catch (ex) {
|
|
45
|
+
// The process exists but we can't signal it: sandboxed/different uid (POSIX
|
|
46
|
+
// EPERM) or `OpenProcess` access-denied (Windows EACCES). Treat as alive.
|
|
47
|
+
// ESRCH and everything else mean dead.
|
|
48
|
+
const code = (ex as NodeJS.ErrnoException)?.code;
|
|
49
|
+
return code === 'EPERM' || code === 'EACCES';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function rehydrateSubagents(
|
|
54
|
+
subagents:
|
|
55
|
+
| (Omit<AgentSession, 'lastActivity' | 'phaseSince'> & { lastActivity: string; phaseSince: string })[]
|
|
56
|
+
| undefined,
|
|
57
|
+
): AgentSession[] | undefined {
|
|
58
|
+
if (subagents == null || subagents.length === 0) return undefined;
|
|
59
|
+
return subagents.map(s => ({
|
|
60
|
+
...s,
|
|
61
|
+
lastActivity: new Date(s.lastActivity),
|
|
62
|
+
phaseSince: new Date(s.phaseSince),
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function describeToolInput(toolName: string, toolInput: Record<string, unknown>): string {
|
|
67
|
+
let detail: string | undefined;
|
|
68
|
+
switch (toolName) {
|
|
69
|
+
case 'Bash':
|
|
70
|
+
detail = toolInput.command as string | undefined;
|
|
71
|
+
break;
|
|
72
|
+
case 'Edit':
|
|
73
|
+
case 'MultiEdit':
|
|
74
|
+
case 'Write':
|
|
75
|
+
case 'Read':
|
|
76
|
+
detail = toolInput.file_path as string | undefined;
|
|
77
|
+
break;
|
|
78
|
+
case 'Grep':
|
|
79
|
+
case 'Glob':
|
|
80
|
+
detail = toolInput.pattern as string | undefined;
|
|
81
|
+
break;
|
|
82
|
+
case 'WebFetch':
|
|
83
|
+
detail = toolInput.url as string | undefined;
|
|
84
|
+
break;
|
|
85
|
+
case 'WebSearch':
|
|
86
|
+
detail = toolInput.query as string | undefined;
|
|
87
|
+
break;
|
|
88
|
+
case 'NotebookEdit':
|
|
89
|
+
detail = toolInput.notebook_path as string | undefined;
|
|
90
|
+
break;
|
|
91
|
+
case 'ExitPlanMode':
|
|
92
|
+
detail = extractPlanSummary(toolInput);
|
|
93
|
+
break;
|
|
94
|
+
case 'AskUserQuestion':
|
|
95
|
+
detail = extractQuestionDetails(toolInput)?.text;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return detail != null ? `${toolName}(${detail})` : toolName;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Maps a Claude Code tool name to its UX-relevant prompt kind. `ExitPlanMode` and
|
|
103
|
+
* `AskUserQuestion` are the two tools whose semantics differ from a regular permission
|
|
104
|
+
* request — everything else falls through to the generic tool kind. */
|
|
105
|
+
export function classifyPermissionKind(toolName: string): PendingPermissionKind {
|
|
106
|
+
switch (toolName) {
|
|
107
|
+
case 'ExitPlanMode':
|
|
108
|
+
return 'plan';
|
|
109
|
+
case 'AskUserQuestion':
|
|
110
|
+
return 'question';
|
|
111
|
+
default:
|
|
112
|
+
return 'tool';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Extracts a short, scannable summary from an ExitPlanMode plan body. Prefers the first
|
|
117
|
+
* Markdown heading (stripped of leading `#`s) so the plan's title surfaces; falls back to
|
|
118
|
+
* the first non-empty line if no heading appears. Capped at {@link summaryMaxLength} with an
|
|
119
|
+
* ellipsis. */
|
|
120
|
+
export function extractPlanSummary(toolInput: Record<string, unknown>): string | undefined {
|
|
121
|
+
const plan = toolInput.plan as string | undefined;
|
|
122
|
+
if (!plan) return undefined;
|
|
123
|
+
|
|
124
|
+
let heading: string | undefined;
|
|
125
|
+
let firstNonEmpty: string | undefined;
|
|
126
|
+
for (const line of plan.split(/\r?\n/)) {
|
|
127
|
+
const trimmed = line.trim();
|
|
128
|
+
if (!trimmed) continue;
|
|
129
|
+
|
|
130
|
+
if (trimmed.startsWith('#')) {
|
|
131
|
+
const stripped = trimmed.replace(/^#+\s*/, '').trim();
|
|
132
|
+
if (stripped) {
|
|
133
|
+
heading = stripped;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
firstNonEmpty ??= trimmed;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const summary = heading ?? firstNonEmpty;
|
|
142
|
+
if (!summary) return undefined;
|
|
143
|
+
|
|
144
|
+
return summary.length > summaryMaxLength ? `${summary.slice(0, summaryMaxLength).trimEnd()}…` : summary;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Extracts the leading question text + total question count from an AskUserQuestion call.
|
|
148
|
+
* Returns undefined if the input doesn't carry a recognisable `questions` array. */
|
|
149
|
+
export function extractQuestionDetails(
|
|
150
|
+
toolInput: Record<string, unknown>,
|
|
151
|
+
): { text: string; count: number } | undefined {
|
|
152
|
+
const questions = toolInput.questions as ReadonlyArray<Record<string, unknown>> | undefined;
|
|
153
|
+
if (!Array.isArray(questions) || questions.length === 0) return undefined;
|
|
154
|
+
|
|
155
|
+
const first = questions[0]?.question;
|
|
156
|
+
if (typeof first !== 'string') return undefined;
|
|
157
|
+
|
|
158
|
+
const trimmed = first.trim();
|
|
159
|
+
if (!trimmed) return undefined;
|
|
160
|
+
|
|
161
|
+
const text = trimmed.length > summaryMaxLength ? `${trimmed.slice(0, summaryMaxLength).trimEnd()}…` : trimmed;
|
|
162
|
+
return { text: text, count: questions.length };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Returns the file path a file-mutating tool is targeting, or `undefined` for non-mutating /
|
|
166
|
+
* non-file tools. `Read` is intentionally excluded — "working on a file" means writing to it.
|
|
167
|
+
* Reads are surfaced separately via {@link getToolReadPath} so consumers (e.g. the treemap
|
|
168
|
+
* activity overlay) can render reads with a distinct visual treatment. */
|
|
169
|
+
export function getToolFilePath(toolName: string, toolInput: Record<string, unknown> | undefined): string | undefined {
|
|
170
|
+
if (toolInput == null) return undefined;
|
|
171
|
+
|
|
172
|
+
switch (toolName) {
|
|
173
|
+
case 'Edit':
|
|
174
|
+
case 'MultiEdit':
|
|
175
|
+
case 'Write':
|
|
176
|
+
return toolInput.file_path as string | undefined;
|
|
177
|
+
case 'NotebookEdit':
|
|
178
|
+
return toolInput.notebook_path as string | undefined;
|
|
179
|
+
default:
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Returns the file path a read-only file tool is targeting, or `undefined` for non-read /
|
|
185
|
+
* non-file tools. Mirrors {@link getToolFilePath} but for `Read`/`NotebookRead`. */
|
|
186
|
+
export function getToolReadPath(toolName: string, toolInput: Record<string, unknown> | undefined): string | undefined {
|
|
187
|
+
if (toolInput == null) return undefined;
|
|
188
|
+
|
|
189
|
+
switch (toolName) {
|
|
190
|
+
case 'Read':
|
|
191
|
+
return toolInput.file_path as string | undefined;
|
|
192
|
+
case 'NotebookRead':
|
|
193
|
+
return toolInput.notebook_path as string | undefined;
|
|
194
|
+
default:
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
}
|