@gitkraken/core-gitlens 0.7.1 → 0.8.0
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 +48 -1
- package/dist/git/cache.d.ts +18 -5
- package/dist/git/cache.js +26 -8
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +5 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/errors.d.ts +28 -1
- package/dist/git/errors.js +45 -1
- package/dist/git/errors.js.map +1 -1
- package/dist/git/providers/branches.d.ts +5 -1
- package/dist/git/providers/commits.d.ts +24 -1
- package/dist/git/providers/config.d.ts +7 -1
- package/dist/git/providers/operations.d.ts +6 -0
- package/dist/git/providers/provider.d.ts +17 -0
- package/dist/git/providers/refs.d.ts +38 -3
- package/dist/git/providers/revision.d.ts +5 -1
- package/dist/git/providers/staging.d.ts +12 -0
- package/dist/git/providers/worktrees.d.ts +23 -3
- package/dist/git/run.types.d.ts +6 -0
- package/dist/git-cli/cliGitProvider.d.ts +17 -1
- package/dist/git-cli/cliGitProvider.js +37 -1
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +12 -2
- package/dist/git-cli/exec/git.js +48 -17
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +4 -1
- package/dist/git-cli/exec/gitQueue.js +1 -1
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +10 -1
- package/dist/git-cli/providers/branches.js +15 -8
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +23 -1
- package/dist/git-cli/providers/commits.js +57 -8
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.js +4 -3
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +1 -0
- package/dist/git-cli/providers/operations.js +39 -3
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.js +20 -41
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +2 -2
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +15 -3
- package/dist/git-cli/providers/refs.js +115 -10
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/revision.d.ts +3 -1
- package/dist/git-cli/providers/revision.js +9 -5
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +8 -0
- package/dist/git-cli/providers/staging.js +59 -7
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +31 -2
- package/dist/git-cli/providers/worktrees.js +75 -7
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/ipc/discovery.js +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
- package/dist/plus/git-github/api/github.d.ts +64 -3
- package/dist/plus/git-github/api/github.js +237 -24
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
- package/dist/plus/git-github/providers/github/branches.js +2 -1
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
- package/dist/plus/git-github/providers/github/refs.js +4 -4
- package/dist/plus/git-github/providers/github/refs.js.map +1 -1
- package/dist/plus/git-github/providers/github/revision.d.ts +3 -1
- package/dist/plus/git-github/providers/github/revision.js +1 -1
- package/dist/plus/git-github/providers/github/revision.js.map +1 -1
- package/dist/plus/integrations/collectionMetadata.d.ts +48 -3
- package/dist/plus/integrations/collectionMetadata.js +138 -8
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/errors.d.ts +3 -1
- package/dist/plus/integrations/errors.js +7 -3
- package/dist/plus/integrations/errors.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +6 -3
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +36 -10
- package/dist/plus/integrations/integrationService.js +16 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +107 -37
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +129 -14
- package/dist/plus/integrations/models/gitHostIntegration.js +142 -18
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +117 -11
- package/dist/plus/integrations/models/integration.js +175 -13
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
- package/dist/plus/integrations/models/issuesIntegration.js +42 -10
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +14 -18
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
- package/dist/plus/integrations/providers/azure/models.js +112 -1
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +73 -3
- package/dist/plus/integrations/providers/azureDevOps.js +117 -3
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +2 -2
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +48 -2
- package/dist/plus/integrations/providers/bitbucket-server.js +51 -1
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +45 -2
- package/dist/plus/integrations/providers/bitbucket.js +41 -2
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +49 -5
- package/dist/plus/integrations/providers/github.js +102 -7
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +1 -1
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +49 -2
- package/dist/plus/integrations/providers/gitlab.js +80 -4
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
- package/dist/plus/integrations/providers/jira-server.js +5 -8
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +9 -0
- package/dist/plus/integrations/providers/jira.js +13 -1
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/linear.js +1 -1
- package/dist/plus/integrations/providers/models.d.ts +13 -2
- package/dist/plus/integrations/providers/models.js +11 -1
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
- package/dist/plus/integrations/providers/providerErrors.js +10 -1
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +60 -1
- package/dist/plus/integrations/providers/providersApi.js +137 -2
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
- package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/providers/utils.d.ts +1 -1
- package/dist/plus/integrations/reads/broaden.js +1 -1
- package/dist/plus/integrations/reads/context.d.ts +1 -1
- package/dist/plus/integrations/reads/counts.js +1 -1
- package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
- package/dist/plus/integrations/reads/currentAccount.js +46 -0
- package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
- package/dist/plus/integrations/reads/drains.d.ts +5 -2
- package/dist/plus/integrations/reads/drains.js +8 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +1 -1
- package/dist/plus/integrations/reads/hierarchy.utils.js +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
- package/dist/plus/integrations/reads/issueBatch.js +193 -48
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +1 -1
- package/dist/plus/integrations/reads/issues.js +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequests.js +3 -3
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js +4 -4
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +87 -6
- package/dist/plus/integrations/results.js +9 -2
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/utils/env/node/exec.js +3 -3
- package/dist/utils/env/node/exec.js.map +1 -1
- package/docs/integrations.md +175 -35
- package/docs/kepler-git-write-api-parity.md +239 -0
- package/docs/kepler-read-api-parity.md +75 -28
- package/package.json +1 -1
- package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
- package/dist/plus/integrations/reads/trackerIssue.js +0 -60
- package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitQueue.js","names":[],"sources":["../../../../git-cli/src/exec/gitQueue.ts"],"sourcesContent":["import type { GitCommandPriority } from './exec.types.js';\n\ninterface QueuedCommand {\n\trun: () => Promise<unknown>;\n\tresolve: (value: unknown) => void;\n\treject: (reason: unknown) => void;\n\tqueuedAt: number;\n\tpriority: GitCommandPriority;\n\tsignal?: AbortSignal;\n\tabortHandler?: () => void;\n}\n\n/** Priority levels in descending order (highest first) */\nconst priorities: GitCommandPriority[] = ['interactive', 'normal', 'background'];\n\n/** How many extra slots interactive commands can use when at capacity */\nconst interactiveBurstCapacity = 2;\n\nfunction abortReason(signal: AbortSignal): Error {\n\treturn signal.reason instanceof Error ? signal.reason : new Error('Aborted');\n}\n\nexport interface GitQueueConfig {\n\t/** Maximum number of concurrent git processes. Defaults to 7. */\n\tmaxConcurrent?: number;\n\t/** Maximum number of queued commands per priority level. Defaults to 500. Set to 0 to disable. */\n\tmaxQueueDepth?: number;\n}\n\nexport interface GitQueueHooks {\n\t/** Called when a queued command waited longer than 1 second before executing */\n\tonSlowQueue?(info: {\n\t\tpriority: GitCommandPriority;\n\t\twaitTime: number;\n\t\tactive: number;\n\t\tqueued: Record<GitCommandPriority, number>;\n\t\tmaxConcurrent: number;\n\t}): void;\n}\n\n/**\n * Priority-based concurrent queue for git command execution.\n *\n * Implements a multi-level feedback queue with:\n * - Configurable max concurrent processes\n * - Strict priority ordering (interactive > normal > background)\n * - Burst capacity for interactive commands under pressure\n *\n * Capacity rules (with limit N, burst B=2):\n * - All priorities share N slots normally\n * - When at capacity, interactive can burst up to N+B total\n *\n * Scheduling rules:\n * - Higher priority preempts: if interactive is waiting, normal/background queue\n * - Lower priority yields: background won't run if normal is waiting\n */\nexport class GitQueue {\n\tprivate readonly _queues = new Map<GitCommandPriority, QueuedCommand[]>([\n\t\t['interactive', []],\n\t\t['normal', []],\n\t\t['background', []],\n\t]);\n\n\tprivate _activeCount = 0;\n\tprivate _disposed = false;\n\n\tconstructor(\n\t\tprivate readonly _config: GitQueueConfig = {},\n\t\tprivate readonly _hooks: GitQueueHooks = {},\n\t) {}\n\n\tdispose(): void {\n\t\tthis._disposed = true;\n\t\tfor (const queue of this._queues.values()) {\n\t\t\tfor (const cmd of queue) {\n\t\t\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\t\t}\n\t\t\t\tcmd.reject(new Error('GitQueue disposed'));\n\t\t\t}\n\t\t\tqueue.length = 0;\n\t\t}\n\t}\n\n\t/** Get the configured max concurrent processes */\n\tprivate get maxConcurrent(): number {\n\t\treturn this._config.maxConcurrent ?? 7;\n\t}\n\n\t/** Update configuration (e.g., when user changes settings) */\n\tupdateConfig(config: Partial<GitQueueConfig>): void {\n\t\tif (config.maxConcurrent != null && config.maxConcurrent > 0) {\n\t\t\tthis._config.maxConcurrent = config.maxConcurrent;\n\t\t}\n\t\tif (config.maxQueueDepth != null && config.maxQueueDepth > 0) {\n\t\t\tthis._config.maxQueueDepth = config.maxQueueDepth;\n\t\t}\n\t}\n\n\t/** Check if a command at the given priority can execute immediately */\n\tprivate canRunNow(priority: GitCommandPriority): boolean {\n\t\t// Must yield to higher priority waiting\n\t\tif (this.hasHigherPriorityWaiting(priority)) return false;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\t// Under normal limit - all priorities can run\n\t\tif (this._activeCount < max) return true;\n\n\t\t// At or over normal limit - only interactive can burst\n\t\tif (priority === 'interactive' && this._activeCount < max + interactiveBurstCapacity) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** Check if any higher-priority commands are waiting */\n\tprivate hasHigherPriorityWaiting(priority: GitCommandPriority): boolean {\n\t\tfor (const p of priorities) {\n\t\t\tif (p === priority) return false;\n\t\t\tif (this._queues.get(p)!.length > 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Execute a git command with the specified priority.\n\t *\n\t * When `signal` is provided:\n\t * - If already aborted, rejects immediately without running.\n\t * - If aborted while queued, the command is removed from the queue and rejected before it ever runs.\n\t * - If aborted while running, the in-flight spawn must honor the same signal separately\n\t * (callers pass it via `runOpts.cancellation`); the queue does not interrupt running work.\n\t */\n\trun<T>(priority: GitCommandPriority, fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n\t\tif (this._disposed) {\n\t\t\treturn Promise.reject(new Error('GitQueue disposed'));\n\t\t}\n\n\t\tif (signal?.aborted) {\n\t\t\treturn Promise.reject(abortReason(signal));\n\t\t}\n\n\t\tif (!this.canRunNow(priority)) {\n\t\t\treturn this.enqueue(fn, priority, signal);\n\t\t}\n\n\t\treturn this.runcore(fn);\n\t}\n\n\tprivate async runcore<T>(fn: () => Promise<T>): Promise<T> {\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis._activeCount--;\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\tprivate enqueue<T>(fn: () => Promise<T>, priority: GitCommandPriority, signal?: AbortSignal): Promise<T> {\n\t\tconst queue = this._queues.get(priority)!;\n\t\tconst maxDepth = this._config.maxQueueDepth ?? 500;\n\t\tif (maxDepth > 0 && queue.length >= maxDepth) {\n\t\t\treturn Promise.reject(new Error(`GitQueue '${priority}' queue is full (${maxDepth} commands pending)`));\n\t\t}\n\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst cmd: QueuedCommand = {\n\t\t\t\trun: fn,\n\t\t\t\tresolve: resolve as (value: unknown) => void,\n\t\t\t\treject: reject,\n\t\t\t\tqueuedAt: Date.now(),\n\t\t\t\tpriority: priority,\n\t\t\t\tsignal: signal,\n\t\t\t};\n\n\t\t\tif (signal != null) {\n\t\t\t\tcmd.abortHandler = () => {\n\t\t\t\t\tconst idx = queue.indexOf(cmd);\n\t\t\t\t\t// If still queued, remove and reject so it never runs.\n\t\t\t\t\t// If already dequeued, the running command should honor the signal at its own layer.\n\t\t\t\t\tif (idx !== -1) {\n\t\t\t\t\t\tqueue.splice(idx, 1);\n\t\t\t\t\t\tcmd.reject(abortReason(signal));\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener('abort', cmd.abortHandler, { once: true });\n\t\t\t}\n\n\t\t\tqueue.push(cmd);\n\t\t});\n\t}\n\n\tprivate processQueues(): void {\n\t\tif (this._disposed) return;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\tfor (const priority of priorities) {\n\t\t\tconst queue = this._queues.get(priority)!;\n\t\t\tconst limit = priority === 'interactive' ? max + interactiveBurstCapacity : max;\n\n\t\t\twhile (queue.length > 0 && this._activeCount < limit && !this.hasHigherPriorityWaiting(priority)) {\n\t\t\t\tthis.runQueued(queue.shift()!);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate runQueued(cmd: QueuedCommand): void {\n\t\t// Detach the abort listener now that the command has left the queue — any subsequent\n\t\t// abort must be handled by the running spawn itself (via runOpts.cancellation).\n\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\tcmd.abortHandler = undefined;\n\t\t}\n\n\t\tconst waitTime = Date.now() - cmd.queuedAt;\n\t\tif (waitTime > 1000) {\n\t\t\tthis._hooks.onSlowQueue?.({\n\t\t\t\tpriority: cmd.priority,\n\t\t\t\twaitTime: waitTime,\n\t\t\t\tactive: this._activeCount,\n\t\t\t\tqueued: {\n\t\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t\t},\n\t\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t\t});\n\t\t}\n\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\tcmd.run()\n\t\t\t\t.then(cmd.resolve, cmd.reject)\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis._activeCount--;\n\t\t\t\t\tthis.processQueues();\n\t\t\t\t});\n\t\t} catch (ex) {\n\t\t\tthis._activeCount--;\n\t\t\tcmd.reject(ex);\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\t/** Returns current queue statistics for diagnostics */\n\tgetStats(): { active: number; queued: Record<GitCommandPriority, number>; maxConcurrent: number } {\n\t\treturn {\n\t\t\tactive: this._activeCount,\n\t\t\tqueued: {\n\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t},\n\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t};\n\t}\n}\n\n/**\n * Git global options that consume the next positional arg as their value\n * (e.g. `--work-tree <path>`). Long-form `--name=value` is already skipped by\n * the leading-dash check, so only the separated form needs explicit handling.\n */\nconst optionsTakingValue = new Set([\n\t'-c',\n\t'-C',\n\t'--git-dir',\n\t'--work-tree',\n\t'--namespace',\n\t'--exec-path',\n\t'--super-prefix',\n\t'--config-env',\n\t'--attr-source',\n\t'--list-cmds',\n]);\n\n/** Extracts the primary git subcommand from an arg list, skipping global options and their values. */\nexport function getPrimaryGitCommand(args: readonly (string | undefined)[]): string | undefined {\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst a = args[i];\n\t\tif (a == null) continue;\n\t\tif (optionsTakingValue.has(a)) {\n\t\t\tconst next = args[i + 1];\n\t\t\tif (next != null && !next.startsWith('-')) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (a.startsWith('-')) continue;\n\n\t\treturn a;\n\t}\n\treturn undefined;\n}\n\n/**\n * Infers a queue priority from the git command being invoked.\n *\n * Intentionally narrow: only returns 'background' for commands that are\n * *always* read-only AND *always* potentially expensive. Polymorphic commands\n * like `log` and `rev-list` (which can be quick bounded lookups or full-history\n * walks) are deliberately omitted — call sites that perform heavy walks must\n * pass `priority: 'background'` explicitly. Never upgrades to 'interactive'.\n *\n * No subcommand awareness (e.g. `stash list`, `branch -l`): the risk of\n * misclassifying a write subcommand as background outweighs the gain.\n */\nexport function inferGitCommandPriority(args: readonly (string | undefined)[]): GitCommandPriority {\n\tswitch (getPrimaryGitCommand(args)) {\n\t\tcase 'for-each-ref':\n\t\tcase 'shortlog':\n\t\tcase 'reflog':\n\t\tcase 'name-rev':\n\t\tcase 'describe':\n\t\tcase 'cherry':\n\t\tcase 'count-objects':\n\t\tcase 'fsck':\n\t\t\treturn 'background';\n\t\tdefault:\n\t\t\treturn 'normal';\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gitQueue.js","names":[],"sources":["../../../../git-cli/src/exec/gitQueue.ts"],"sourcesContent":["import type { GitCommandPriority } from './exec.types.js';\n\ninterface QueuedCommand {\n\trun: () => Promise<unknown>;\n\tresolve: (value: unknown) => void;\n\treject: (reason: unknown) => void;\n\tqueuedAt: number;\n\tpriority: GitCommandPriority;\n\tsignal?: AbortSignal;\n\tabortHandler?: () => void;\n}\n\n/** Priority levels in descending order (highest first) */\nconst priorities: GitCommandPriority[] = ['interactive', 'normal', 'background'];\n\n/** How many extra slots interactive commands can use when at capacity */\nconst interactiveBurstCapacity = 2;\n\nfunction abortReason(signal: AbortSignal): Error {\n\treturn signal.reason instanceof Error ? signal.reason : new Error('Aborted');\n}\n\nexport interface GitQueueConfig {\n\t/**\n\t * Maximum number of concurrent git processes. Defaults to 20, the default of GitLens'\n\t * `advanced.git.maxConcurrentProcesses`.\n\t */\n\tmaxConcurrent?: number;\n\t/** Maximum number of queued commands per priority level. Defaults to 500. Set to 0 to disable. */\n\tmaxQueueDepth?: number;\n}\n\nexport interface GitQueueHooks {\n\t/** Called when a queued command waited longer than 1 second before executing */\n\tonSlowQueue?(info: {\n\t\tpriority: GitCommandPriority;\n\t\twaitTime: number;\n\t\tactive: number;\n\t\tqueued: Record<GitCommandPriority, number>;\n\t\tmaxConcurrent: number;\n\t}): void;\n}\n\n/**\n * Priority-based concurrent queue for git command execution.\n *\n * Implements a multi-level feedback queue with:\n * - Configurable max concurrent processes\n * - Strict priority ordering (interactive > normal > background)\n * - Burst capacity for interactive commands under pressure\n *\n * Capacity rules (with limit N, burst B=2):\n * - All priorities share N slots normally\n * - When at capacity, interactive can burst up to N+B total\n *\n * Scheduling rules:\n * - Higher priority preempts: if interactive is waiting, normal/background queue\n * - Lower priority yields: background won't run if normal is waiting\n */\nexport class GitQueue {\n\tprivate readonly _queues = new Map<GitCommandPriority, QueuedCommand[]>([\n\t\t['interactive', []],\n\t\t['normal', []],\n\t\t['background', []],\n\t]);\n\n\tprivate _activeCount = 0;\n\tprivate _disposed = false;\n\n\tconstructor(\n\t\tprivate readonly _config: GitQueueConfig = {},\n\t\tprivate readonly _hooks: GitQueueHooks = {},\n\t) {}\n\n\tdispose(): void {\n\t\tthis._disposed = true;\n\t\tfor (const queue of this._queues.values()) {\n\t\t\tfor (const cmd of queue) {\n\t\t\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\t\t}\n\t\t\t\tcmd.reject(new Error('GitQueue disposed'));\n\t\t\t}\n\t\t\tqueue.length = 0;\n\t\t}\n\t}\n\n\t/** Get the configured max concurrent processes */\n\tprivate get maxConcurrent(): number {\n\t\treturn this._config.maxConcurrent ?? 20;\n\t}\n\n\t/** Update configuration (e.g., when user changes settings) */\n\tupdateConfig(config: Partial<GitQueueConfig>): void {\n\t\tif (config.maxConcurrent != null && config.maxConcurrent > 0) {\n\t\t\tthis._config.maxConcurrent = config.maxConcurrent;\n\t\t}\n\t\tif (config.maxQueueDepth != null && config.maxQueueDepth > 0) {\n\t\t\tthis._config.maxQueueDepth = config.maxQueueDepth;\n\t\t}\n\t}\n\n\t/** Check if a command at the given priority can execute immediately */\n\tprivate canRunNow(priority: GitCommandPriority): boolean {\n\t\t// Must yield to higher priority waiting\n\t\tif (this.hasHigherPriorityWaiting(priority)) return false;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\t// Under normal limit - all priorities can run\n\t\tif (this._activeCount < max) return true;\n\n\t\t// At or over normal limit - only interactive can burst\n\t\tif (priority === 'interactive' && this._activeCount < max + interactiveBurstCapacity) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** Check if any higher-priority commands are waiting */\n\tprivate hasHigherPriorityWaiting(priority: GitCommandPriority): boolean {\n\t\tfor (const p of priorities) {\n\t\t\tif (p === priority) return false;\n\t\t\tif (this._queues.get(p)!.length > 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Execute a git command with the specified priority.\n\t *\n\t * When `signal` is provided:\n\t * - If already aborted, rejects immediately without running.\n\t * - If aborted while queued, the command is removed from the queue and rejected before it ever runs.\n\t * - If aborted while running, the in-flight spawn must honor the same signal separately\n\t * (callers pass it via `runOpts.cancellation`); the queue does not interrupt running work.\n\t */\n\trun<T>(priority: GitCommandPriority, fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n\t\tif (this._disposed) {\n\t\t\treturn Promise.reject(new Error('GitQueue disposed'));\n\t\t}\n\n\t\tif (signal?.aborted) {\n\t\t\treturn Promise.reject(abortReason(signal));\n\t\t}\n\n\t\tif (!this.canRunNow(priority)) {\n\t\t\treturn this.enqueue(fn, priority, signal);\n\t\t}\n\n\t\treturn this.runcore(fn);\n\t}\n\n\tprivate async runcore<T>(fn: () => Promise<T>): Promise<T> {\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis._activeCount--;\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\tprivate enqueue<T>(fn: () => Promise<T>, priority: GitCommandPriority, signal?: AbortSignal): Promise<T> {\n\t\tconst queue = this._queues.get(priority)!;\n\t\tconst maxDepth = this._config.maxQueueDepth ?? 500;\n\t\tif (maxDepth > 0 && queue.length >= maxDepth) {\n\t\t\treturn Promise.reject(new Error(`GitQueue '${priority}' queue is full (${maxDepth} commands pending)`));\n\t\t}\n\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst cmd: QueuedCommand = {\n\t\t\t\trun: fn,\n\t\t\t\tresolve: resolve as (value: unknown) => void,\n\t\t\t\treject: reject,\n\t\t\t\tqueuedAt: Date.now(),\n\t\t\t\tpriority: priority,\n\t\t\t\tsignal: signal,\n\t\t\t};\n\n\t\t\tif (signal != null) {\n\t\t\t\tcmd.abortHandler = () => {\n\t\t\t\t\tconst idx = queue.indexOf(cmd);\n\t\t\t\t\t// If still queued, remove and reject so it never runs.\n\t\t\t\t\t// If already dequeued, the running command should honor the signal at its own layer.\n\t\t\t\t\tif (idx !== -1) {\n\t\t\t\t\t\tqueue.splice(idx, 1);\n\t\t\t\t\t\tcmd.reject(abortReason(signal));\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener('abort', cmd.abortHandler, { once: true });\n\t\t\t}\n\n\t\t\tqueue.push(cmd);\n\t\t});\n\t}\n\n\tprivate processQueues(): void {\n\t\tif (this._disposed) return;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\tfor (const priority of priorities) {\n\t\t\tconst queue = this._queues.get(priority)!;\n\t\t\tconst limit = priority === 'interactive' ? max + interactiveBurstCapacity : max;\n\n\t\t\twhile (queue.length > 0 && this._activeCount < limit && !this.hasHigherPriorityWaiting(priority)) {\n\t\t\t\tthis.runQueued(queue.shift()!);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate runQueued(cmd: QueuedCommand): void {\n\t\t// Detach the abort listener now that the command has left the queue — any subsequent\n\t\t// abort must be handled by the running spawn itself (via runOpts.cancellation).\n\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\tcmd.abortHandler = undefined;\n\t\t}\n\n\t\tconst waitTime = Date.now() - cmd.queuedAt;\n\t\tif (waitTime > 1000) {\n\t\t\tthis._hooks.onSlowQueue?.({\n\t\t\t\tpriority: cmd.priority,\n\t\t\t\twaitTime: waitTime,\n\t\t\t\tactive: this._activeCount,\n\t\t\t\tqueued: {\n\t\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t\t},\n\t\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t\t});\n\t\t}\n\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\tcmd.run()\n\t\t\t\t.then(cmd.resolve, cmd.reject)\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis._activeCount--;\n\t\t\t\t\tthis.processQueues();\n\t\t\t\t});\n\t\t} catch (ex) {\n\t\t\tthis._activeCount--;\n\t\t\tcmd.reject(ex);\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\t/** Returns current queue statistics for diagnostics */\n\tgetStats(): { active: number; queued: Record<GitCommandPriority, number>; maxConcurrent: number } {\n\t\treturn {\n\t\t\tactive: this._activeCount,\n\t\t\tqueued: {\n\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t},\n\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t};\n\t}\n}\n\n/**\n * Git global options that consume the next positional arg as their value\n * (e.g. `--work-tree <path>`). Long-form `--name=value` is already skipped by\n * the leading-dash check, so only the separated form needs explicit handling.\n */\nconst optionsTakingValue = new Set([\n\t'-c',\n\t'-C',\n\t'--git-dir',\n\t'--work-tree',\n\t'--namespace',\n\t'--exec-path',\n\t'--super-prefix',\n\t'--config-env',\n\t'--attr-source',\n\t'--list-cmds',\n]);\n\n/** Extracts the primary git subcommand from an arg list, skipping global options and their values. */\nexport function getPrimaryGitCommand(args: readonly (string | undefined)[]): string | undefined {\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst a = args[i];\n\t\tif (a == null) continue;\n\t\tif (optionsTakingValue.has(a)) {\n\t\t\tconst next = args[i + 1];\n\t\t\tif (next != null && !next.startsWith('-')) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (a.startsWith('-')) continue;\n\n\t\treturn a;\n\t}\n\treturn undefined;\n}\n\n/**\n * Infers a queue priority from the git command being invoked.\n *\n * Intentionally narrow: only returns 'background' for commands that are\n * *always* read-only AND *always* potentially expensive. Polymorphic commands\n * like `log` and `rev-list` (which can be quick bounded lookups or full-history\n * walks) are deliberately omitted — call sites that perform heavy walks must\n * pass `priority: 'background'` explicitly. Never upgrades to 'interactive'.\n *\n * No subcommand awareness (e.g. `stash list`, `branch -l`): the risk of\n * misclassifying a write subcommand as background outweighs the gain.\n */\nexport function inferGitCommandPriority(args: readonly (string | undefined)[]): GitCommandPriority {\n\tswitch (getPrimaryGitCommand(args)) {\n\t\tcase 'for-each-ref':\n\t\tcase 'shortlog':\n\t\tcase 'reflog':\n\t\tcase 'name-rev':\n\t\tcase 'describe':\n\t\tcase 'cherry':\n\t\tcase 'count-objects':\n\t\tcase 'fsck':\n\t\t\treturn 'background';\n\t\tdefault:\n\t\t\treturn 'normal';\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -16,7 +16,9 @@ export declare class BranchesGitSubProvider implements GitBranchesSubProvider {
|
|
|
16
16
|
private readonly cache;
|
|
17
17
|
private readonly provider;
|
|
18
18
|
constructor(context: GitServiceContext, git: Git, cache: Cache, provider: CliGitProviderInternal);
|
|
19
|
-
getBranch(repoPath: string, name?: string,
|
|
19
|
+
getBranch(repoPath: string, name?: string, options?: {
|
|
20
|
+
force?: boolean;
|
|
21
|
+
}, cancellation?: AbortSignal): Promise<GitBranch | undefined>;
|
|
20
22
|
private getCurrentBranch;
|
|
21
23
|
getBranches(repoPath: string, options?: {
|
|
22
24
|
filter?: (b: GitBranch) => boolean;
|
|
@@ -59,6 +61,13 @@ export declare class BranchesGitSubProvider implements GitBranchesSubProvider {
|
|
|
59
61
|
deleteLocalBranch(repoPath: string, names: string | string[], options?: {
|
|
60
62
|
force?: boolean;
|
|
61
63
|
}): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Drops what GitLens keeps for a local branch beyond its ref, for both ways one is deleted
|
|
66
|
+
* (`deleteLocalBranch` and `refs.deleteReference`). The persisted gk metadata goes too, not just the
|
|
67
|
+
* cached resolution: `getBaseBranchName` reads `branch.<ref>.gk-merge-base` before falling back to the
|
|
68
|
+
* reflog, so leaving it behind would hand a later branch reusing this name its predecessor's base.
|
|
69
|
+
*/
|
|
70
|
+
forgetDeletedBranch(repoPath: string, name: string): Promise<void>;
|
|
62
71
|
/**
|
|
63
72
|
* Drops the cached and persisted per-branch metadata for whichever of `names` no longer exists. Only
|
|
64
73
|
* for the partial-failure path — one extra `for-each-ref` is cheap while already handling an error,
|
|
@@ -34,7 +34,8 @@ var BranchesGitSubProvider = class {
|
|
|
34
34
|
this.cache = cache;
|
|
35
35
|
this.provider = provider;
|
|
36
36
|
}
|
|
37
|
-
async getBranch(repoPath, name, cancellation) {
|
|
37
|
+
async getBranch(repoPath, name, options, cancellation) {
|
|
38
|
+
if (options?.force) this.cache.evictCaches(repoPath, "branches");
|
|
38
39
|
if (name != null) {
|
|
39
40
|
const { values: [branch] } = await this.getBranches(repoPath, { filter: (b) => b.name === name }, cancellation);
|
|
40
41
|
return branch;
|
|
@@ -244,7 +245,7 @@ var BranchesGitSubProvider = class {
|
|
|
244
245
|
if (mergeTarget == null && options?.associatedPullRequest != null) {
|
|
245
246
|
const pr = await options.associatedPullRequest;
|
|
246
247
|
if (pr?.refs?.base != null) {
|
|
247
|
-
const branch = await this.getBranch(repoPath, ref, cancellation);
|
|
248
|
+
const branch = await this.getBranch(repoPath, ref, void 0, cancellation);
|
|
248
249
|
if (branch == null) return void 0;
|
|
249
250
|
mergeTarget = `${branch.remoteName}/${pr.refs.base.branch}`;
|
|
250
251
|
if (pr.stack == null) this.storeMergeTargetBranchName(repoPath, ref, mergeTarget, { skipInvalidation: ["branchOverviews"] });
|
|
@@ -460,10 +461,7 @@ var BranchesGitSubProvider = class {
|
|
|
460
461
|
];
|
|
461
462
|
try {
|
|
462
463
|
await this.git.run({ cwd: repoPath }, ...args);
|
|
463
|
-
for (const branch of branches)
|
|
464
|
-
this.cache.deleteBaseBranchName(repoPath, branch);
|
|
465
|
-
await this.provider.config.removeGkConfigBranchSection(repoPath, branch);
|
|
466
|
-
}
|
|
464
|
+
for (const branch of branches) await this.forgetDeletedBranch(repoPath, branch);
|
|
467
465
|
this.context.hooks?.cache?.onReset?.(repoPath, "branches");
|
|
468
466
|
this.context.hooks?.repository?.onChanged?.(repoPath, ["heads"]);
|
|
469
467
|
} catch (ex) {
|
|
@@ -491,6 +489,16 @@ var BranchesGitSubProvider = class {
|
|
|
491
489
|
}
|
|
492
490
|
}
|
|
493
491
|
/**
|
|
492
|
+
* Drops what GitLens keeps for a local branch beyond its ref, for both ways one is deleted
|
|
493
|
+
* (`deleteLocalBranch` and `refs.deleteReference`). The persisted gk metadata goes too, not just the
|
|
494
|
+
* cached resolution: `getBaseBranchName` reads `branch.<ref>.gk-merge-base` before falling back to the
|
|
495
|
+
* reflog, so leaving it behind would hand a later branch reusing this name its predecessor's base.
|
|
496
|
+
*/
|
|
497
|
+
async forgetDeletedBranch(repoPath, name) {
|
|
498
|
+
this.cache.deleteBaseBranchName(repoPath, name);
|
|
499
|
+
await this.provider.config.removeGkConfigBranchSection(repoPath, name);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
494
502
|
* Drops the cached and persisted per-branch metadata for whichever of `names` no longer exists. Only
|
|
495
503
|
* for the partial-failure path — one extra `for-each-ref` is cheap while already handling an error,
|
|
496
504
|
* and keeps the success path free of it.
|
|
@@ -511,8 +519,7 @@ var BranchesGitSubProvider = class {
|
|
|
511
519
|
for (const name of names) {
|
|
512
520
|
if (surviving.has(name)) continue;
|
|
513
521
|
anyDeleted = true;
|
|
514
|
-
this.
|
|
515
|
-
await this.provider.config.removeGkConfigBranchSection(repoPath, name);
|
|
522
|
+
await this.forgetDeletedBranch(repoPath, name);
|
|
516
523
|
}
|
|
517
524
|
return anyDeleted;
|
|
518
525
|
} catch {
|