@gitkraken/core-gitlens 0.5.113 → 0.5.114

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.
Files changed (241) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/git/cache.d.ts +4 -0
  3. package/dist/git/cache.d.ts.map +1 -1
  4. package/dist/git/cache.js +33 -0
  5. package/dist/git/cache.js.map +1 -1
  6. package/dist/git/context.d.ts +10 -0
  7. package/dist/git/context.d.ts.map +1 -1
  8. package/dist/git/context.js.map +1 -1
  9. package/dist/git/errors.d.ts +6 -3
  10. package/dist/git/errors.d.ts.map +1 -1
  11. package/dist/git/errors.js +9 -1
  12. package/dist/git/errors.js.map +1 -1
  13. package/dist/git/features.d.ts +1 -1
  14. package/dist/git/features.d.ts.map +1 -1
  15. package/dist/git/features.js +38 -0
  16. package/dist/git/features.js.map +1 -1
  17. package/dist/git/gitHealth.d.ts +153 -0
  18. package/dist/git/gitHealth.d.ts.map +1 -0
  19. package/dist/git/gitHealth.js +353 -0
  20. package/dist/git/gitHealth.js.map +1 -0
  21. package/dist/git/models/search.d.ts +6 -3
  22. package/dist/git/models/search.d.ts.map +1 -1
  23. package/dist/git/models/search.js +5 -1
  24. package/dist/git/models/search.js.map +1 -1
  25. package/dist/git/parsers/diffParser.d.ts +8 -2
  26. package/dist/git/parsers/diffParser.d.ts.map +1 -1
  27. package/dist/git/parsers/diffParser.js +27 -4
  28. package/dist/git/parsers/diffParser.js.map +1 -1
  29. package/dist/git/providers/config.d.ts +36 -3
  30. package/dist/git/providers/config.d.ts.map +1 -1
  31. package/dist/git/providers/graph.d.ts +9 -0
  32. package/dist/git/providers/graph.d.ts.map +1 -1
  33. package/dist/git/providers/maintenance.d.ts +222 -0
  34. package/dist/git/providers/maintenance.d.ts.map +1 -0
  35. package/dist/git/providers/maintenance.js +20 -0
  36. package/dist/git/providers/maintenance.js.map +1 -0
  37. package/dist/git/providers/operations.d.ts +10 -0
  38. package/dist/git/providers/operations.d.ts.map +1 -1
  39. package/dist/git/providers/pausedOperations.d.ts +3 -0
  40. package/dist/git/providers/pausedOperations.d.ts.map +1 -1
  41. package/dist/git/providers/provider.d.ts +2 -0
  42. package/dist/git/providers/provider.d.ts.map +1 -1
  43. package/dist/git/providers/tags.d.ts +3 -0
  44. package/dist/git/providers/tags.d.ts.map +1 -1
  45. package/dist/git/repositoryService.d.ts +1 -0
  46. package/dist/git/repositoryService.d.ts.map +1 -1
  47. package/dist/git/repositoryService.js.map +1 -1
  48. package/dist/git/run.types.d.ts +8 -0
  49. package/dist/git/run.types.d.ts.map +1 -1
  50. package/dist/git/service.js +3 -0
  51. package/dist/git/service.js.map +1 -1
  52. package/dist/git/utils/search.utils.d.ts.map +1 -1
  53. package/dist/git/utils/search.utils.js +112 -5
  54. package/dist/git/utils/search.utils.js.map +1 -1
  55. package/dist/git/watching/watchService.d.ts +3 -0
  56. package/dist/git/watching/watchService.d.ts.map +1 -1
  57. package/dist/git/watching/watchService.js +8 -0
  58. package/dist/git/watching/watchService.js.map +1 -1
  59. package/dist/git-cli/cliGitProvider.d.ts +11 -0
  60. package/dist/git-cli/cliGitProvider.d.ts.map +1 -1
  61. package/dist/git-cli/cliGitProvider.js +12 -0
  62. package/dist/git-cli/cliGitProvider.js.map +1 -1
  63. package/dist/git-cli/exec/git.d.ts +23 -1
  64. package/dist/git-cli/exec/git.d.ts.map +1 -1
  65. package/dist/git-cli/exec/git.js +83 -8
  66. package/dist/git-cli/exec/git.js.map +1 -1
  67. package/dist/git-cli/exec/gitQueue.d.ts +2 -0
  68. package/dist/git-cli/exec/gitQueue.d.ts.map +1 -1
  69. package/dist/git-cli/exec/gitQueue.js +19 -17
  70. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  71. package/dist/git-cli/parsers/logParser.d.ts.map +1 -1
  72. package/dist/git-cli/parsers/logParser.js +4 -1
  73. package/dist/git-cli/parsers/logParser.js.map +1 -1
  74. package/dist/git-cli/providers/blame.d.ts.map +1 -1
  75. package/dist/git-cli/providers/blame.js +4 -7
  76. package/dist/git-cli/providers/blame.js.map +1 -1
  77. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  78. package/dist/git-cli/providers/branches.js +13 -3
  79. package/dist/git-cli/providers/branches.js.map +1 -1
  80. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  81. package/dist/git-cli/providers/commits.js +34 -3
  82. package/dist/git-cli/providers/commits.js.map +1 -1
  83. package/dist/git-cli/providers/config.d.ts +27 -0
  84. package/dist/git-cli/providers/config.d.ts.map +1 -1
  85. package/dist/git-cli/providers/config.js +31 -6
  86. package/dist/git-cli/providers/config.js.map +1 -1
  87. package/dist/git-cli/providers/graph.d.ts +8 -0
  88. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  89. package/dist/git-cli/providers/graph.js +85 -6
  90. package/dist/git-cli/providers/graph.js.map +1 -1
  91. package/dist/git-cli/providers/maintenance.d.ts +306 -0
  92. package/dist/git-cli/providers/maintenance.d.ts.map +1 -0
  93. package/dist/git-cli/providers/maintenance.js +2129 -0
  94. package/dist/git-cli/providers/maintenance.js.map +1 -0
  95. package/dist/git-cli/providers/operations.d.ts +1 -0
  96. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  97. package/dist/git-cli/providers/operations.js +8 -0
  98. package/dist/git-cli/providers/operations.js.map +1 -1
  99. package/dist/git-cli/providers/pausedOperations.d.ts +1 -0
  100. package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
  101. package/dist/git-cli/providers/pausedOperations.js +1 -1
  102. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  103. package/dist/git-cli/providers/tags.d.ts +3 -0
  104. package/dist/git-cli/providers/tags.d.ts.map +1 -1
  105. package/dist/git-cli/providers/tags.js +23 -1
  106. package/dist/git-cli/providers/tags.js.map +1 -1
  107. package/dist/plus/agents/agentCapabilities.d.ts +77 -0
  108. package/dist/plus/agents/agentCapabilities.d.ts.map +1 -0
  109. package/dist/plus/agents/agentCapabilities.js +197 -0
  110. package/dist/plus/agents/agentCapabilities.js.map +1 -0
  111. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +77 -13
  112. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
  113. package/dist/plus/agents/providers/claudeCodeTranscript.js +263 -55
  114. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  115. package/dist/plus/agents/providers/{claudeCodeProvider.d.ts → gkAgentProvider.d.ts} +52 -19
  116. package/dist/plus/agents/providers/gkAgentProvider.d.ts.map +1 -0
  117. package/dist/plus/agents/providers/{claudeCodeProvider.js → gkAgentProvider.js} +935 -262
  118. package/dist/plus/agents/providers/gkAgentProvider.js.map +1 -0
  119. package/dist/plus/agents/types.d.ts +113 -35
  120. package/dist/plus/agents/types.d.ts.map +1 -1
  121. package/dist/plus/agents/types.js +7 -4
  122. package/dist/plus/agents/types.js.map +1 -1
  123. package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
  124. package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
  125. package/dist/plus/ai/prompts.d.ts +4 -0
  126. package/dist/plus/ai/prompts.d.ts.map +1 -1
  127. package/dist/plus/ai/prompts.js +59 -4
  128. package/dist/plus/ai/prompts.js.map +1 -1
  129. package/dist/plus/git-github/api/github.d.ts +44 -1
  130. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  131. package/dist/plus/git-github/api/github.js +318 -25
  132. package/dist/plus/git-github/api/github.js.map +1 -1
  133. package/dist/plus/git-github/api/issueSearchQuery.d.ts +13 -0
  134. package/dist/plus/git-github/api/issueSearchQuery.d.ts.map +1 -1
  135. package/dist/plus/git-github/api/issueSearchQuery.js +41 -0
  136. package/dist/plus/git-github/api/issueSearchQuery.js.map +1 -1
  137. package/dist/plus/git-github/providers/github/blame.d.ts.map +1 -1
  138. package/dist/plus/git-github/providers/github/blame.js +2 -1
  139. package/dist/plus/git-github/providers/github/blame.js.map +1 -1
  140. package/dist/plus/integrations/integrationService.d.ts +11 -0
  141. package/dist/plus/integrations/integrationService.d.ts.map +1 -1
  142. package/dist/plus/integrations/integrationService.js +4 -0
  143. package/dist/plus/integrations/integrationService.js.map +1 -1
  144. package/dist/plus/integrations/manager.d.ts +26 -0
  145. package/dist/plus/integrations/manager.d.ts.map +1 -1
  146. package/dist/plus/integrations/models/gitHostIntegration.d.ts +31 -0
  147. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
  148. package/dist/plus/integrations/models/gitHostIntegration.js +31 -0
  149. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  150. package/dist/plus/integrations/models/integration.d.ts +1 -1
  151. package/dist/plus/integrations/models/integration.d.ts.map +1 -1
  152. package/dist/plus/integrations/models/integration.js.map +1 -1
  153. package/dist/plus/integrations/providers/github.d.ts +9 -0
  154. package/dist/plus/integrations/providers/github.d.ts.map +1 -1
  155. package/dist/plus/integrations/providers/github.js +7 -0
  156. package/dist/plus/integrations/providers/github.js.map +1 -1
  157. package/dist/plus/integrations/reads/broaden.d.ts +47 -10
  158. package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
  159. package/dist/plus/integrations/reads/broaden.js +144 -33
  160. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  161. package/dist/plus/integrations/reads/filters.d.ts +18 -0
  162. package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
  163. package/dist/plus/integrations/reads/filters.js +37 -1
  164. package/dist/plus/integrations/reads/filters.js.map +1 -1
  165. package/dist/plus/integrations/reads/issueBatch.d.ts +51 -0
  166. package/dist/plus/integrations/reads/issueBatch.d.ts.map +1 -0
  167. package/dist/plus/integrations/reads/issueBatch.js +91 -0
  168. package/dist/plus/integrations/reads/issueBatch.js.map +1 -0
  169. package/dist/plus/integrations/reads/sweeps.d.ts.map +1 -1
  170. package/dist/plus/integrations/reads/sweeps.js +5 -3
  171. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  172. package/dist/utils/promiseCache.d.ts +19 -0
  173. package/dist/utils/promiseCache.d.ts.map +1 -1
  174. package/dist/utils/promiseCache.js +30 -0
  175. package/dist/utils/promiseCache.js.map +1 -1
  176. package/dist/utils/resourceUsage.d.ts +5 -0
  177. package/dist/utils/resourceUsage.d.ts.map +1 -0
  178. package/dist/utils/resourceUsage.js +2 -0
  179. package/dist/utils/resourceUsage.js.map +1 -0
  180. package/dist/utils/string.d.ts +12 -0
  181. package/dist/utils/string.d.ts.map +1 -1
  182. package/dist/utils/string.js +36 -1
  183. package/dist/utils/string.js.map +1 -1
  184. package/docs/integrations.md +29 -25
  185. package/docs/kepler-read-api-parity.md +12 -4
  186. package/package.json +11 -3
  187. package/src/git/cache.ts +36 -0
  188. package/src/git/context.ts +11 -0
  189. package/src/git/errors.ts +13 -1
  190. package/src/git/features.ts +51 -0
  191. package/src/git/gitHealth.ts +522 -0
  192. package/src/git/models/search.ts +19 -4
  193. package/src/git/parsers/diffParser.ts +27 -4
  194. package/src/git/providers/config.ts +42 -1
  195. package/src/git/providers/graph.ts +12 -0
  196. package/src/git/providers/maintenance.ts +224 -0
  197. package/src/git/providers/operations.ts +10 -0
  198. package/src/git/providers/pausedOperations.ts +3 -0
  199. package/src/git/providers/provider.ts +2 -0
  200. package/src/git/providers/tags.ts +1 -0
  201. package/src/git/repositoryService.ts +1 -0
  202. package/src/git/run.types.ts +8 -0
  203. package/src/git/service.ts +3 -0
  204. package/src/git/utils/search.utils.ts +129 -5
  205. package/src/git/watching/watchService.ts +10 -0
  206. package/src/git-cli/cliGitProvider.ts +25 -0
  207. package/src/git-cli/exec/git.ts +120 -6
  208. package/src/git-cli/exec/gitQueue.ts +19 -17
  209. package/src/git-cli/parsers/logParser.ts +4 -1
  210. package/src/git-cli/providers/blame.ts +3 -8
  211. package/src/git-cli/providers/branches.ts +28 -8
  212. package/src/git-cli/providers/commits.ts +34 -2
  213. package/src/git-cli/providers/config.ts +38 -6
  214. package/src/git-cli/providers/graph.ts +107 -7
  215. package/src/git-cli/providers/maintenance.ts +2599 -0
  216. package/src/git-cli/providers/operations.ts +11 -0
  217. package/src/git-cli/providers/pausedOperations.ts +7 -2
  218. package/src/git-cli/providers/tags.ts +36 -1
  219. package/src/plus/agents/agentCapabilities.ts +286 -0
  220. package/src/plus/agents/providers/claudeCodeTranscript.ts +313 -58
  221. package/src/plus/agents/providers/{claudeCodeProvider.ts → gkAgentProvider.ts} +1123 -277
  222. package/src/plus/agents/types.ts +137 -40
  223. package/src/plus/ai/models/promptTemplates.ts +1 -1
  224. package/src/plus/ai/prompts.ts +62 -4
  225. package/src/plus/git-github/api/github.ts +353 -24
  226. package/src/plus/git-github/api/issueSearchQuery.ts +49 -1
  227. package/src/plus/git-github/providers/github/blame.ts +2 -1
  228. package/src/plus/integrations/integrationService.ts +15 -0
  229. package/src/plus/integrations/manager.ts +26 -0
  230. package/src/plus/integrations/models/gitHostIntegration.ts +48 -0
  231. package/src/plus/integrations/models/integration.ts +1 -0
  232. package/src/plus/integrations/providers/github.ts +18 -0
  233. package/src/plus/integrations/reads/broaden.ts +282 -70
  234. package/src/plus/integrations/reads/filters.ts +39 -1
  235. package/src/plus/integrations/reads/issueBatch.ts +197 -0
  236. package/src/plus/integrations/reads/sweeps.ts +19 -12
  237. package/src/utils/promiseCache.ts +43 -0
  238. package/src/utils/resourceUsage.ts +5 -0
  239. package/src/utils/string.ts +38 -1
  240. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +0 -1
  241. package/dist/plus/agents/providers/claudeCodeProvider.js.map +0 -1
@@ -698,6 +698,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
698
698
  editor?: string;
699
699
  interactive?: boolean;
700
700
  programmaticEditor?: boolean;
701
+ autosquash?: boolean;
701
702
  messageEditor?: string;
702
703
  onto?: string;
703
704
  updateRefs?: boolean;
@@ -729,6 +730,16 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
729
730
  }
730
731
  }
731
732
 
733
+ if (options?.autosquash != null) {
734
+ if (options.autosquash && options.programmaticEditor) {
735
+ throw new Error('rebase: autosquash cannot be combined with programmaticEditor');
736
+ }
737
+
738
+ // `--no-autosquash` is passed explicitly when `false` — omitting the flag would let a
739
+ // `rebase.autosquash=true` git config fold fixups anyway.
740
+ args.push(options.autosquash ? '--autosquash' : '--no-autosquash');
741
+ }
742
+
732
743
  // Drive per-commit message editing (the combined message a `squash` produces, or a `reword`).
733
744
  // `GIT_EDITOR` (not `core.editor`) is what git's interactive-rebase backend honors for the `reword`
734
745
  // amend step, so set it on the environment; also set `core.editor` config as a fallback.
@@ -559,7 +559,12 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
559
559
  @debug()
560
560
  async continuePausedOperation(
561
561
  repoPath: string,
562
- options?: { allowEmpty?: boolean; skip?: boolean; messageEditor?: string },
562
+ options?: {
563
+ allowEmpty?: boolean;
564
+ skip?: boolean;
565
+ messageEditor?: string;
566
+ editorEnv?: Record<string, string>;
567
+ },
563
568
  ): Promise<void> {
564
569
  const scope = getScopedLogger();
565
570
 
@@ -579,7 +584,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
579
584
  let env: Record<string, string | undefined> | undefined;
580
585
  if (options?.messageEditor) {
581
586
  configs.push('-c', `core.editor=${options.messageEditor}`);
582
- env = { GIT_EDITOR: options.messageEditor };
587
+ env = { ...options.editorEnv, GIT_EDITOR: options.messageEditor };
583
588
  }
584
589
 
585
590
  try {
@@ -5,7 +5,7 @@ import { GitTag } from '../../git/models/tag.js';
5
5
  import type { GitTagsSubProvider } from '../../git/providers/tags.js';
6
6
  import type { TagSortOptions } from '../../git/utils/sorting.js';
7
7
  import { sortTags } from '../../git/utils/sorting.js';
8
- import { filterMap } from '../../utils/array.js';
8
+ import { ensureArray, filterMap } from '../../utils/array.js';
9
9
  import { isCancellationError } from '../../utils/cancellation.js';
10
10
  import { debug } from '../../utils/decorators/log.js';
11
11
  import { getScopedLogger } from '../../utils/logger.scoped.js';
@@ -186,4 +186,39 @@ export class TagsGitSubProvider implements GitTagsSubProvider {
186
186
  );
187
187
  }
188
188
  }
189
+
190
+ @debug()
191
+ async pushTag(
192
+ repoPath: string,
193
+ name: string | string[],
194
+ remote: string,
195
+ options?: { force?: boolean },
196
+ ): Promise<void> {
197
+ const names = ensureArray(name);
198
+ const args = ['push'];
199
+ if (options?.force) {
200
+ args.push('--force');
201
+ }
202
+
203
+ args.push(remote, ...names.map(n => `refs/tags/${n}`));
204
+
205
+ try {
206
+ await this.git.run({ cwd: repoPath }, ...args);
207
+ } catch (ex) {
208
+ throw getGitCommandError(
209
+ 'tag',
210
+ ex as GitError,
211
+ reason =>
212
+ new TagError(
213
+ {
214
+ reason: reason,
215
+ action: 'push',
216
+ tag: names.join(', '),
217
+ gitCommand: { repoPath: repoPath, args: args },
218
+ },
219
+ ex as GitError,
220
+ ),
221
+ );
222
+ }
223
+ }
189
224
  }
@@ -0,0 +1,286 @@
1
+ import type { AgentHookEvent } from './types.js';
2
+ import { canonicalBlockingHookEvents, canonicalNonBlockingHookEvents } from './types.js';
3
+
4
+ /** `gk ai hook` client id — the id the GitKraken CLI stamps onto every relayed hook event. NOT
5
+ * the same namespace as {@link AgentProviderId}. */
6
+ export type AgentHookClientId = 'claude-code' | 'codex' | 'copilot' | 'opencode';
7
+
8
+ /** GitLens session provider id — what lands on `AgentSession.providerId` and in telemetry. NOT
9
+ * the same namespace as {@link AgentHookClientId}. */
10
+ export type AgentProviderId = 'claudeCode' | 'codex' | 'copilot' | 'opencode';
11
+
12
+ /** Icon-font glyph name used to badge the agent in the UI. Every member must name a `ThemeIcon` id
13
+ * that actually exists: either a codicon glyph name (`codicons-map.ts` is generated from VS Code's
14
+ * own font, so it isn't ours to extend) or a GitLens-contributed `gitlens-*` id from the `glicons`
15
+ * font, built from SVGs in `images/icons/`. An agent with no mark of its own uses `robot` — a name
16
+ * with no glyph renders as tofu, it does not fall back. */
17
+ export type AgentIconName = 'claude' | 'openai' | 'copilot' | 'gitlens-provider-opencode' | 'robot';
18
+
19
+ /**
20
+ * Flat, data-only description of one supported `gk ai hook` client. Mirrors how the GitKraken CLI
21
+ * models its own clients (`internal/actions/aihook/events.json` + `registry.go`) so the two stay
22
+ * comparable: the CLI relays each agent's native event and tool names verbatim, and this table is
23
+ * what translates them into the canonical (Claude Code) vocabulary.
24
+ */
25
+ export interface AgentCapabilities {
26
+ /** The `gk ai hook` client id events arrive stamped with. */
27
+ readonly hookClientId: AgentHookClientId;
28
+ /** The GitLens session provider id — see {@link AgentProviderId}. */
29
+ readonly providerId: AgentProviderId;
30
+ readonly displayName: string;
31
+ readonly icon: AgentIconName;
32
+
33
+ /** Native event name → canonical event. Omitted when the agent's native names are already
34
+ * canonical. */
35
+ readonly eventMap?: Readonly<Record<string, AgentHookEvent>>;
36
+ /** Escape hatch for the cases where the native event name alone can't determine the canonical
37
+ * event and the payload has to be consulted. Tried BEFORE {@link eventMap}; returning
38
+ * `undefined` falls through to it. `hookInput` is the ROOT of the JSON the agent piped to
39
+ * `gk ai hook run` (what the CLI relays verbatim as `hookInput`), not a pre-unwrapped payload —
40
+ * navigate the agent's own nesting from there. */
41
+ readonly resolveEvent?: (
42
+ nativeEvent: string,
43
+ hookInput: Record<string, unknown> | undefined,
44
+ ) => AgentHookEvent | undefined;
45
+ /** Native tool name → canonical (Claude Code) tool name. Omitted when already canonical. */
46
+ readonly toolNameMap?: Readonly<Record<string, string>>;
47
+
48
+ /** Native event names to register as non-blocking hooks at install time. `undefined` means
49
+ * "pass no event flags and let `gk` apply its own per-client defaults". */
50
+ readonly installEvents?: readonly string[];
51
+ /** Native event names to register as blocking hooks at install time. `undefined` means
52
+ * "pass no event flags and let `gk` apply its own per-client defaults". */
53
+ readonly installBlockingEvents?: readonly string[];
54
+
55
+ /** The agent can be installed with blocking hooks, so GitLens can answer a permission ask. */
56
+ readonly supportsBlockingPermissions: boolean;
57
+ /** The agent writes an on-disk transcript GitLens can tail for titles/prompts. */
58
+ readonly supportsTranscripts: boolean;
59
+ /** A past session can be resumed from its cwd. */
60
+ readonly supportsResume: boolean;
61
+ /** The agent multiplexes concurrent sessions in one process, so a pid does not identify a
62
+ * session (matches the CLI's `pidSharingClients`). */
63
+ readonly sharesPids: boolean;
64
+
65
+ /** Extra step the agent's own host requires before installed hooks will actually fire. Undefined
66
+ * when installing is sufficient. Not a computed state — we cannot detect whether the step has been
67
+ * done, so consumers surface this unconditionally whenever hooks are installed. */
68
+ readonly manualActivation?: string;
69
+ }
70
+
71
+ const canonicalHookEvents = new Set<string>([...canonicalNonBlockingHookEvents, ...canonicalBlockingHookEvents]);
72
+
73
+ function asRecord(value: unknown): Record<string, unknown> | undefined {
74
+ return typeof value === 'object' && value != null ? (value as Record<string, unknown>) : undefined;
75
+ }
76
+
77
+ function isCanonicalHookEvent(event: string): event is AgentHookEvent {
78
+ return canonicalHookEvents.has(event);
79
+ }
80
+
81
+ /** Claude Code's install set: its full native vocabulary minus the worktree events, which the CLI
82
+ * also skips by default (`skippedDefaultEvents` in its `events.json`) and GitLens has no use for. */
83
+ const claudeCodeInstallEvents: readonly AgentHookEvent[] = canonicalNonBlockingHookEvents.filter(
84
+ e => e !== 'WorktreeCreate' && e !== 'WorktreeRemove',
85
+ );
86
+
87
+ /** Exported because Claude Code is the wire default: an event with no `providerId` comes from a CLI
88
+ * too old to stamp one, which predates every other client. */
89
+ export const claudeCodeCapabilities: AgentCapabilities = {
90
+ hookClientId: 'claude-code',
91
+ providerId: 'claudeCode',
92
+ displayName: 'Claude Code',
93
+ icon: 'claude',
94
+ // No `eventMap`/`toolNameMap` — Claude Code's vocabulary IS the canonical one.
95
+ installEvents: claudeCodeInstallEvents,
96
+ installBlockingEvents: canonicalBlockingHookEvents,
97
+ supportsBlockingPermissions: true,
98
+ supportsTranscripts: true,
99
+ supportsResume: true,
100
+ sharesPids: false,
101
+ };
102
+
103
+ const codexCapabilities: AgentCapabilities = {
104
+ hookClientId: 'codex',
105
+ providerId: 'codex',
106
+ displayName: 'Codex',
107
+ icon: 'openai',
108
+ // No `eventMap` — Codex emits canonical event names already.
109
+ toolNameMap: {
110
+ apply_patch: 'Edit',
111
+ // `update_plan` is deliberately NOT mapped to `ExitPlanMode`: it's a todo-list update, not a
112
+ // plan-approval ask, and mapping it would classify routine progress as a permission prompt.
113
+ // Left unmapped so it falls through to the generic tool path.
114
+ },
115
+ // `undefined` install sets: let `gk` apply its per-client defaults for now. Blocking permissions
116
+ // are supported by the client but not requested until a later phase.
117
+ supportsBlockingPermissions: true,
118
+ supportsTranscripts: false,
119
+ supportsResume: false,
120
+ // The CLI lists codex in `pidSharingClients` — it multiplexes sessions in one process.
121
+ sharesPids: true,
122
+ // Verified empirically, not speculative: running an identical Codex session with
123
+ // `--dangerously-bypass-hook-trust` fires the installed hooks immediately (a session record
124
+ // appears); without that flag, zero records — Codex silently refuses to run command hooks it
125
+ // hasn't trusted yet, with no log line or warning of any kind. Trust is granted via `/hooks`
126
+ // inside interactive Codex and is bound to the hook's hash, so a reinstall invalidates it. There
127
+ // is no known way to detect trust state from outside Codex, so this hint is unconditional.
128
+ manualActivation:
129
+ "Codex won't run these hooks until you trust them — run `/hooks` in Codex. You'll need to trust them again if the hooks are reinstalled.",
130
+ };
131
+
132
+ const copilotCapabilities: AgentCapabilities = {
133
+ hookClientId: 'copilot',
134
+ providerId: 'copilot',
135
+ displayName: 'GitHub Copilot CLI',
136
+ icon: 'copilot',
137
+ eventMap: {
138
+ // Copilot's event names are otherwise canonical; `ErrorOccurred` is the one with no canonical
139
+ // equivalent, so it maps onto Claude's turn-ended-in-error event (which derives to `idle`).
140
+ ErrorOccurred: 'StopFailure',
141
+ },
142
+ // Copilot's own documented tool alias table.
143
+ toolNameMap: {
144
+ bash: 'Bash',
145
+ // `powershell` is deliberately absent. Aliasing it to `Bash` would only be worth the lost
146
+ // label fidelity (a PowerShell call rendering as `Bash(...)`) if it bought the command detail
147
+ // `describeToolInput` extracts for shells — and it can't: Copilot relays its args as
148
+ // `hookInput.toolInput` (camelCase), a key nothing here reads, so no tool input reaches us at
149
+ // all. Pure label loss today; revisit if Copilot's tool inputs ever become readable.
150
+ view: 'Read',
151
+ create: 'Write',
152
+ edit: 'Edit',
153
+ str_replace_editor: 'Edit',
154
+ apply_patch: 'Edit',
155
+ grep: 'Grep',
156
+ rg: 'Grep',
157
+ glob: 'Glob',
158
+ web_fetch: 'WebFetch',
159
+ web_search: 'WebSearch',
160
+ ask_user: 'AskUserQuestion',
161
+ },
162
+ supportsBlockingPermissions: true,
163
+ supportsTranscripts: false,
164
+ supportsResume: false,
165
+ sharesPids: false,
166
+ };
167
+
168
+ /** Reads the status type out of an OpenCode `session.status` hook input. The CLI's generated
169
+ * OpenCode plugin nests the raw SDK event under `hook_payload.event` (`buildHookInput` sets
170
+ * `hook_payload: payload`, and the generic event hook passes `{ event }`), so the full path from
171
+ * the hook-input root is `hook_payload.event.properties.status.type`. The payload is untyped JSON,
172
+ * so every hop is checked rather than cast. */
173
+ function getOpenCodeSessionStatusType(hookInput: Record<string, unknown> | undefined): string | undefined {
174
+ const hookPayload = asRecord(hookInput?.hook_payload);
175
+ const event = asRecord(hookPayload?.event);
176
+ const properties = asRecord(event?.properties);
177
+ const status = asRecord(properties?.status);
178
+ const type = status?.type;
179
+
180
+ return typeof type === 'string' ? type : undefined;
181
+ }
182
+
183
+ const openCodeCapabilities: AgentCapabilities = {
184
+ hookClientId: 'opencode',
185
+ providerId: 'opencode',
186
+ displayName: 'OpenCode',
187
+ icon: 'gitlens-provider-opencode',
188
+ eventMap: {
189
+ 'session.created': 'SessionStart',
190
+ 'session.deleted': 'SessionEnd',
191
+ // `session.idle` is deprecated in OpenCode's own source in favor of `session.status`, which is
192
+ // why both are handled — older builds still emit it.
193
+ 'session.idle': 'Stop',
194
+ 'session.error': 'StopFailure',
195
+ 'session.compacted': 'PostCompact',
196
+ 'permission.asked': 'PermissionRequest',
197
+ 'permission.replied': 'ElicitationResult',
198
+ 'tool.execute.before': 'PreToolUse',
199
+ 'tool.execute.after': 'PostToolUse',
200
+ // `session.updated` is intentionally absent — it has no canonical analogue.
201
+ // `session.status` is resolved by `resolveEvent` below, since its meaning is in the payload.
202
+ },
203
+ // Only `idle` resolves. `busy` is deliberately unmapped, and so is everything else (`retry`
204
+ // included): the canonical event this returns doesn't just pick a status, it selects a branch of
205
+ // the provider's state-machine switch, so a mapping inherits that event's ENTIRE handler. Naming
206
+ // `PostToolUse` here would also clear a pending permission ask, decrement the parallel-tool
207
+ // refcount, and schedule file decorations away — all wrong for a tick OpenCode emits
208
+ // independently of any tool lifecycle, and the ask-clearing is visibly wrong (the agent is still
209
+ // blocked on it). There is no tool-free canonical event meaning "resumed working", and `busy`
210
+ // carries no tool semantics to justify inventing one.
211
+ resolveEvent: (nativeEvent, hookInput) => {
212
+ if (nativeEvent !== 'session.status') return undefined;
213
+
214
+ return getOpenCodeSessionStatusType(hookInput) === 'idle' ? 'Stop' : undefined;
215
+ },
216
+ toolNameMap: {
217
+ bash: 'Bash',
218
+ read: 'Read',
219
+ write: 'Write',
220
+ edit: 'Edit',
221
+ grep: 'Grep',
222
+ glob: 'Glob',
223
+ webfetch: 'WebFetch',
224
+ websearch: 'WebSearch',
225
+ apply_patch: 'Edit',
226
+ },
227
+ // The CLI hard-errors when asked to install blocking events for opencode.
228
+ supportsBlockingPermissions: false,
229
+ supportsTranscripts: false,
230
+ supportsResume: false,
231
+ sharesPids: false,
232
+ // OpenCode's tool hooks carry no per-call cwd: the CLI's generated plugin supplies the
233
+ // plugin-init directory once, so a session's reported cwd is frozen at that value and never
234
+ // reflects later movement. Deliberately prose and NOT a capability flag — it was one, and
235
+ // nothing could be built on it. Every cwd-driven path in `gkAgentProvider` (the
236
+ // visited-worktree unions, `cwdTimeline` resolution, the `cliSeatedWorktree` unexplained-move
237
+ // clear) reacts only to an OBSERVED difference between successive cwds, so a frozen cwd
238
+ // degrades each one to its already-correct single-value no-op. A flag hands that code no fact
239
+ // it can act on: it explains why the diff never fires, it does not supply the directory the
240
+ // hooks never sent. Promote it back to a field if a surface ever needs to caveat the
241
+ // attribution to the user — that would be its first real consumer.
242
+ };
243
+
244
+ /** Every supported hook client, in registry order. */
245
+ export const agentCapabilities: readonly AgentCapabilities[] = [
246
+ claudeCodeCapabilities,
247
+ codexCapabilities,
248
+ copilotCapabilities,
249
+ openCodeCapabilities,
250
+ ];
251
+
252
+ /** Looks up capabilities by `gk ai hook` client id. Returns `undefined` for clients GitLens has no
253
+ * descriptor for (the CLI supports more than this table does). */
254
+ export function getAgentCapabilities(hookClientId: string): AgentCapabilities | undefined {
255
+ return agentCapabilities.find(c => c.hookClientId === hookClientId);
256
+ }
257
+
258
+ /** Looks up capabilities by GitLens session provider id. */
259
+ export function getAgentCapabilitiesByProviderId(providerId: string): AgentCapabilities | undefined {
260
+ return agentCapabilities.find(c => c.providerId === providerId);
261
+ }
262
+
263
+ /**
264
+ * Translates an agent's native hook event name into the canonical vocabulary: `resolveEvent` first,
265
+ * then `eventMap`, then an identity pass-through for names that are already canonical. Returns
266
+ * `undefined` for anything else — unknown strings are never assumed to be canonical events.
267
+ */
268
+ export function resolveCanonicalHookEvent(
269
+ capabilities: AgentCapabilities,
270
+ nativeEvent: string,
271
+ hookInput?: Record<string, unknown>,
272
+ ): AgentHookEvent | undefined {
273
+ const resolved = capabilities.resolveEvent?.(nativeEvent, hookInput);
274
+ if (resolved != null) return resolved;
275
+
276
+ const mapped = capabilities.eventMap?.[nativeEvent];
277
+ if (mapped != null) return mapped;
278
+
279
+ return isCanonicalHookEvent(nativeEvent) ? nativeEvent : undefined;
280
+ }
281
+
282
+ /** Translates an agent's native tool name into the canonical (Claude Code) tool name, falling back
283
+ * to the input unchanged when the agent has no alias for it. */
284
+ export function resolveCanonicalToolName(capabilities: AgentCapabilities, nativeToolName: string): string {
285
+ return capabilities.toolNameMap?.[nativeToolName] ?? nativeToolName;
286
+ }