@solaqua/gji 0.12.4 → 0.13.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.
Files changed (214) hide show
  1. package/README.md +12 -0
  2. package/dist/application/worktree/catalog.d.ts +31 -0
  3. package/dist/application/worktree/catalog.js +88 -0
  4. package/dist/application/worktree/context-card.d.ts +14 -0
  5. package/dist/application/worktree/context-card.js +12 -0
  6. package/dist/{go-resolver.d.ts → application/worktree/go-resolution.d.ts} +12 -4
  7. package/dist/{go-resolver.js → application/worktree/go-resolution.js} +46 -44
  8. package/dist/application/worktree/read-models.d.ts +31 -0
  9. package/dist/application/worktree/sources.d.ts +7 -0
  10. package/dist/{worktree-sources.js → application/worktree/sources.js} +12 -24
  11. package/dist/{back.d.ts → cli/commands/back.d.ts} +3 -1
  12. package/dist/{back.js → cli/commands/back.js} +8 -6
  13. package/dist/{clean.d.ts → cli/commands/clean.d.ts} +4 -2
  14. package/dist/{clean.js → cli/commands/clean.js} +32 -24
  15. package/dist/{completion.js → cli/commands/completion.js} +2 -2
  16. package/dist/{config-command.d.ts → cli/commands/config-command.d.ts} +2 -0
  17. package/dist/{config-command.js → cli/commands/config-command.js} +7 -5
  18. package/dist/{doctor.d.ts → cli/commands/doctor.d.ts} +2 -0
  19. package/dist/{doctor.js → cli/commands/doctor.js} +23 -25
  20. package/dist/{done.d.ts → cli/commands/done.d.ts} +2 -0
  21. package/dist/{done.js → cli/commands/done.js} +26 -23
  22. package/dist/{go.d.ts → cli/commands/go.d.ts} +6 -1
  23. package/dist/{go.js → cli/commands/go.js} +57 -41
  24. package/dist/{history-command.d.ts → cli/commands/history-command.d.ts} +2 -0
  25. package/dist/{history-command.js → cli/commands/history-command.js} +3 -1
  26. package/dist/{hub.d.ts → cli/commands/hub.d.ts} +7 -3
  27. package/dist/{hub.js → cli/commands/hub.js} +23 -33
  28. package/dist/{init.d.ts → cli/commands/init.d.ts} +3 -1
  29. package/dist/{init.js → cli/commands/init.js} +37 -34
  30. package/dist/{ls.d.ts → cli/commands/ls.d.ts} +4 -2
  31. package/dist/{ls.js → cli/commands/ls.js} +8 -5
  32. package/dist/{new.d.ts → cli/commands/new.d.ts} +6 -2
  33. package/dist/{new.js → cli/commands/new.js} +237 -109
  34. package/dist/{open.d.ts → cli/commands/open.d.ts} +4 -2
  35. package/dist/{open.js → cli/commands/open.js} +19 -12
  36. package/dist/{pr-open.d.ts → cli/commands/pr-open.d.ts} +4 -2
  37. package/dist/{pr-open.js → cli/commands/pr-open.js} +20 -18
  38. package/dist/{pr.d.ts → cli/commands/pr.d.ts} +5 -3
  39. package/dist/{pr.js → cli/commands/pr.js} +34 -41
  40. package/dist/{remove.d.ts → cli/commands/remove.d.ts} +4 -2
  41. package/dist/{remove.js → cli/commands/remove.js} +23 -17
  42. package/dist/{root.d.ts → cli/commands/root.d.ts} +2 -0
  43. package/dist/{root.js → cli/commands/root.js} +4 -2
  44. package/dist/{run-hook.d.ts → cli/commands/run-hook.d.ts} +2 -0
  45. package/dist/{run-hook.js → cli/commands/run-hook.js} +7 -4
  46. package/dist/{status.d.ts → cli/commands/status.d.ts} +2 -0
  47. package/dist/{status.js → cli/commands/status.js} +10 -7
  48. package/dist/{sync-files-command.d.ts → cli/commands/sync-files-command.d.ts} +2 -0
  49. package/dist/{sync-files-command.js → cli/commands/sync-files-command.js} +11 -9
  50. package/dist/{sync.d.ts → cli/commands/sync.d.ts} +2 -0
  51. package/dist/{sync.js → cli/commands/sync.js} +7 -4
  52. package/dist/{task-command.d.ts → cli/commands/task-command.d.ts} +2 -0
  53. package/dist/{task-command.js → cli/commands/task-command.js} +4 -2
  54. package/dist/{undo.d.ts → cli/commands/undo.d.ts} +8 -6
  55. package/dist/{undo.js → cli/commands/undo.js} +44 -34
  56. package/dist/{warp.d.ts → cli/commands/warp.d.ts} +5 -2
  57. package/dist/{warp.js → cli/commands/warp.js} +20 -10
  58. package/dist/cli/dependencies.d.ts +114 -0
  59. package/dist/cli/dependencies.js +118 -0
  60. package/dist/{cli.d.ts → cli/program.d.ts} +4 -2
  61. package/dist/{cli.js → cli/program.js} +108 -124
  62. package/dist/domain/repository/context.d.ts +6 -0
  63. package/dist/domain/repository/context.js +1 -0
  64. package/dist/domain/repository/registry.d.ts +5 -0
  65. package/dist/domain/repository/registry.js +1 -0
  66. package/dist/domain/shared/concurrency.d.ts +1 -0
  67. package/dist/domain/shared/concurrency.js +15 -0
  68. package/dist/domain/worktree/matching.d.ts +4 -0
  69. package/dist/domain/worktree/matching.js +79 -0
  70. package/dist/domain/worktree/policy.d.ts +2 -0
  71. package/dist/domain/worktree/policy.js +58 -0
  72. package/dist/domain/worktree/pr-reference.d.ts +1 -0
  73. package/dist/domain/worktree/pr-reference.js +9 -0
  74. package/dist/{worktree-source.d.ts → domain/worktree/source.d.ts} +1 -1
  75. package/dist/domain/worktree/source.js +1 -0
  76. package/dist/domain/worktree/types.d.ts +5 -0
  77. package/dist/domain/worktree/types.js +1 -0
  78. package/dist/gji-bundle.mjs +7100 -6265
  79. package/dist/index.js +3 -3
  80. package/dist/{dependency-bootstrap.d.ts → infrastructure/bootstrap/dependency-bootstrap.d.ts} +3 -30
  81. package/dist/{dependency-bootstrap.js → infrastructure/bootstrap/dependency-bootstrap.js} +4 -4
  82. package/dist/infrastructure/git/health.d.ts +9 -0
  83. package/dist/infrastructure/git/health.js +44 -0
  84. package/dist/infrastructure/git/refs.d.ts +6 -0
  85. package/dist/{git.js → infrastructure/git/refs.js} +1 -51
  86. package/dist/infrastructure/git/runner.d.ts +2 -0
  87. package/dist/infrastructure/git/runner.js +16 -0
  88. package/dist/{editor.d.ts → infrastructure/integrations/editor.d.ts} +2 -6
  89. package/dist/{pull-requests.d.ts → infrastructure/integrations/pull-requests.d.ts} +3 -11
  90. package/dist/{config.d.ts → infrastructure/persistence/config.d.ts} +3 -17
  91. package/dist/{config.js → infrastructure/persistence/config.js} +2 -17
  92. package/dist/{history.d.ts → infrastructure/persistence/history.d.ts} +2 -5
  93. package/dist/{task.js → infrastructure/persistence/task.js} +1 -1
  94. package/dist/infrastructure/process/command-runner.d.ts +3 -0
  95. package/dist/{hooks.d.ts → infrastructure/process/hooks.d.ts} +2 -12
  96. package/dist/infrastructure/repository/adapters.d.ts +7 -0
  97. package/dist/infrastructure/repository/adapters.js +23 -0
  98. package/dist/infrastructure/repository/context.d.ts +3 -0
  99. package/dist/infrastructure/repository/context.js +20 -0
  100. package/dist/infrastructure/repository/refs.d.ts +3 -0
  101. package/dist/infrastructure/repository/refs.js +37 -0
  102. package/dist/{repo-registry.d.ts → infrastructure/repository/registry.d.ts} +1 -5
  103. package/dist/{repo-registry.js → infrastructure/repository/registry.js} +1 -1
  104. package/dist/infrastructure/repository/worktrees.d.ts +2 -0
  105. package/dist/infrastructure/repository/worktrees.js +48 -0
  106. package/dist/{uv-validation.d.ts → infrastructure/validation/uv.d.ts} +1 -1
  107. package/dist/{uv-validation.js → infrastructure/validation/uv.js} +1 -1
  108. package/dist/infrastructure/worktree/bootstrap.d.ts +3 -0
  109. package/dist/{worktree-bootstrap.js → infrastructure/worktree/bootstrap.js} +7 -10
  110. package/dist/infrastructure/worktree/info.d.ts +6 -0
  111. package/dist/infrastructure/worktree/info.js +61 -0
  112. package/dist/{worktree-management.d.ts → infrastructure/worktree/lifecycle.d.ts} +0 -6
  113. package/dist/{worktree-management.js → infrastructure/worktree/lifecycle.js} +1 -9
  114. package/dist/ports/bootstrap.d.ts +61 -0
  115. package/dist/ports/bootstrap.js +1 -0
  116. package/dist/ports/config.d.ts +21 -0
  117. package/dist/ports/config.js +17 -0
  118. package/dist/ports/editor.d.ts +6 -0
  119. package/dist/ports/editor.js +1 -0
  120. package/dist/ports/git.d.ts +8 -0
  121. package/dist/ports/git.js +1 -0
  122. package/dist/ports/history.d.ts +5 -0
  123. package/dist/ports/history.js +1 -0
  124. package/dist/ports/hooks.d.ts +12 -0
  125. package/dist/ports/hooks.js +1 -0
  126. package/dist/{command-runner.d.ts → ports/process.d.ts} +0 -1
  127. package/dist/ports/process.js +1 -0
  128. package/dist/ports/pull-requests.d.ts +11 -0
  129. package/dist/ports/pull-requests.js +1 -0
  130. package/dist/ports/repository.d.ts +17 -0
  131. package/dist/ports/repository.js +1 -0
  132. package/dist/{bootstrap-output.d.ts → presentation/bootstrap/output.d.ts} +1 -1
  133. package/dist/presentation/bootstrap/preview.d.ts +2 -0
  134. package/dist/{bootstrap-preview.js → presentation/bootstrap/preview.js} +0 -4
  135. package/dist/{shell-completion.js → presentation/shell/completion.js} +5 -4
  136. package/dist/presentation/terminal/context-card.d.ts +2 -0
  137. package/dist/{context-card.js → presentation/terminal/context-card.js} +3 -12
  138. package/dist/presentation/worktree/format.d.ts +4 -0
  139. package/dist/presentation/worktree/format.js +41 -0
  140. package/dist/{worktree-picker.d.ts → presentation/worktree/picker.d.ts} +7 -11
  141. package/dist/{worktree-picker.js → presentation/worktree/picker.js} +36 -191
  142. package/man/man1/gji-back.1 +1 -1
  143. package/man/man1/gji-clean.1 +1 -1
  144. package/man/man1/gji-completion.1 +1 -1
  145. package/man/man1/gji-config.1 +1 -1
  146. package/man/man1/gji-doctor.1 +1 -1
  147. package/man/man1/gji-done.1 +1 -1
  148. package/man/man1/gji-go.1 +1 -1
  149. package/man/man1/gji-history.1 +1 -1
  150. package/man/man1/gji-init.1 +1 -1
  151. package/man/man1/gji-ls.1 +1 -1
  152. package/man/man1/gji-new.1 +6 -3
  153. package/man/man1/gji-open.1 +1 -1
  154. package/man/man1/gji-pr.1 +1 -1
  155. package/man/man1/gji-remove.1 +1 -1
  156. package/man/man1/gji-root.1 +1 -1
  157. package/man/man1/gji-run-hook.1 +1 -1
  158. package/man/man1/gji-status.1 +1 -1
  159. package/man/man1/gji-sync-files.1 +1 -1
  160. package/man/man1/gji-sync.1 +1 -1
  161. package/man/man1/gji-task.1 +1 -1
  162. package/man/man1/gji-undo.1 +1 -1
  163. package/man/man1/gji-warp.1 +1 -1
  164. package/man/man1/gji.1 +2 -2
  165. package/package.json +1 -1
  166. package/dist/bootstrap-preview.d.ts +0 -9
  167. package/dist/context-card.d.ts +0 -1
  168. package/dist/format-bytes.d.ts +0 -1
  169. package/dist/format-bytes.js +0 -14
  170. package/dist/git.d.ts +0 -18
  171. package/dist/repo.d.ts +0 -20
  172. package/dist/repo.js +0 -161
  173. package/dist/worktree-bootstrap.d.ts +0 -24
  174. package/dist/worktree-info.d.ts +0 -37
  175. package/dist/worktree-info.js +0 -123
  176. package/dist/worktree-sources.d.ts +0 -4
  177. /package/dist/{worktree-source.js → application/worktree/read-models.js} +0 -0
  178. /package/dist/{completion.d.ts → cli/commands/completion.d.ts} +0 -0
  179. /package/dist/{headless.d.ts → cli/runtime/headless.d.ts} +0 -0
  180. /package/dist/{headless.js → cli/runtime/headless.js} +0 -0
  181. /package/dist/{paths.d.ts → domain/shared/paths.d.ts} +0 -0
  182. /package/dist/{paths.js → domain/shared/paths.js} +0 -0
  183. /package/dist/{file-sync.d.ts → infrastructure/filesystem/file-sync.d.ts} +0 -0
  184. /package/dist/{file-sync.js → infrastructure/filesystem/file-sync.js} +0 -0
  185. /package/dist/{fs-utils.d.ts → infrastructure/filesystem/fs-utils.d.ts} +0 -0
  186. /package/dist/{fs-utils.js → infrastructure/filesystem/fs-utils.js} +0 -0
  187. /package/dist/{safe-destination.d.ts → infrastructure/filesystem/safe-destination.d.ts} +0 -0
  188. /package/dist/{safe-destination.js → infrastructure/filesystem/safe-destination.js} +0 -0
  189. /package/dist/{browser.d.ts → infrastructure/integrations/browser.d.ts} +0 -0
  190. /package/dist/{browser.js → infrastructure/integrations/browser.js} +0 -0
  191. /package/dist/{editor.js → infrastructure/integrations/editor.js} +0 -0
  192. /package/dist/{pull-requests.js → infrastructure/integrations/pull-requests.js} +0 -0
  193. /package/dist/{history.js → infrastructure/persistence/history.js} +0 -0
  194. /package/dist/{slots.d.ts → infrastructure/persistence/slots.d.ts} +0 -0
  195. /package/dist/{slots.js → infrastructure/persistence/slots.js} +0 -0
  196. /package/dist/{task.d.ts → infrastructure/persistence/task.d.ts} +0 -0
  197. /package/dist/{command-runner.js → infrastructure/process/command-runner.js} +0 -0
  198. /package/dist/{hooks.js → infrastructure/process/hooks.js} +0 -0
  199. /package/dist/{bootstrap-output.js → presentation/bootstrap/output.js} +0 -0
  200. /package/dist/{conflict.d.ts → presentation/prompts/path-conflict.d.ts} +0 -0
  201. /package/dist/{conflict.js → presentation/prompts/path-conflict.js} +0 -0
  202. /package/dist/{shell-completion.d.ts → presentation/shell/completion.d.ts} +0 -0
  203. /package/dist/{shell-handoff.d.ts → presentation/shell/handoff.d.ts} +0 -0
  204. /package/dist/{shell-handoff.js → presentation/shell/handoff.js} +0 -0
  205. /package/dist/{shell-setup.d.ts → presentation/shell/setup.d.ts} +0 -0
  206. /package/dist/{shell-setup.js → presentation/shell/setup.js} +0 -0
  207. /package/dist/{shell.d.ts → presentation/shell/shell.d.ts} +0 -0
  208. /package/dist/{shell.js → presentation/shell/shell.js} +0 -0
  209. /package/dist/{navigation-output.d.ts → presentation/terminal/navigation.d.ts} +0 -0
  210. /package/dist/{navigation-output.js → presentation/terminal/navigation.js} +0 -0
  211. /package/dist/{terminal-text.d.ts → presentation/terminal/text.d.ts} +0 -0
  212. /package/dist/{terminal-text.js → presentation/terminal/text.js} +0 -0
  213. /package/dist/{worktree-prompts.d.ts → presentation/worktree/prompts.d.ts} +0 -0
  214. /package/dist/{worktree-prompts.js → presentation/worktree/prompts.js} +0 -0
@@ -1,13 +1,10 @@
1
1
  import { confirm, isCancel } from "@clack/prompts";
2
- import { loadEffectiveConfig } from "./config.js";
3
- import { isBranchMergedInto, readWorktreeHealth, resolveRemoteDefaultBranch, runGit, } from "./git.js";
4
- import { isHeadless } from "./headless.js";
5
- import { releaseWorktreeSlot } from "./slots.js";
2
+ import { loadLinkedWorktrees } from "../../application/worktree/catalog.js";
3
+ import { buildWorktreePromptEntries, promptForMultipleWorktrees, } from "../../presentation/worktree/picker.js";
4
+ import { defaultConfirmForceDeleteBranch, defaultConfirmForceRemoveWorktree, } from "../../presentation/worktree/prompts.js";
5
+ import { defaultCliDependencies, } from "../dependencies.js";
6
+ import { isHeadless } from "../runtime/headless.js";
6
7
  import { finalizeUndoOperation, recordUndoOperation } from "./undo.js";
7
- import { formatLastCommit, formatUpstreamState, readWorktreeInfos, serializeWorktreeInfo, } from "./worktree-info.js";
8
- import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isSubmoduleWorktreeRemovalError, isWorktreeDeletionError, isWorktreeForceRemovalError, loadLinkedWorktrees, removeWorktree, } from "./worktree-management.js";
9
- import { buildWorktreePromptEntries, promptForMultipleWorktrees, } from "./worktree-picker.js";
10
- import { defaultConfirmForceDeleteBranch, defaultConfirmForceRemoveWorktree, } from "./worktree-prompts.js";
11
8
  export function createCleanCommand(dependencies = {}) {
12
9
  const promptForWorktrees = dependencies.promptForWorktrees ?? defaultPromptForWorktrees;
13
10
  const confirmRemoval = dependencies.confirmRemoval ?? defaultConfirmRemoval;
@@ -15,13 +12,24 @@ export function createCleanCommand(dependencies = {}) {
15
12
  defaultConfirmForceRemoveWorktree;
16
13
  const confirmForceDeleteBranch = dependencies.confirmForceDeleteBranch ?? defaultConfirmForceDeleteBranch;
17
14
  return async function runCleanCommand(options) {
18
- const { linkedWorktrees, repository } = await loadLinkedWorktrees(options.cwd);
15
+ const runtime = options.runtime ?? defaultCliDependencies;
16
+ const { readWorktreeHealth, isBranchMergedInto, resolveRemoteDefaultBranch, runGit, } = runtime.git;
17
+ const { loadEffectiveConfig } = runtime.config;
18
+ const { releaseWorktreeSlot } = runtime.slots;
19
+ const sourceDependencies = {
20
+ ...runtime.repositoryContext,
21
+ ...runtime.repositoryRegistry,
22
+ ...runtime.worktrees,
23
+ };
24
+ const { formatLastCommit, formatUpstreamState, readWorktreeInfos, serializeWorktreeInfo, } = runtime.worktreeInfo;
25
+ const { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isSubmoduleWorktreeRemovalError, isWorktreeDeletionError, isWorktreeForceRemovalError, removeWorktree, } = runtime.worktreeLifecycle;
26
+ const { linkedWorktrees, repository } = await loadLinkedWorktrees(options.cwd, sourceDependencies);
19
27
  const linkedCleanupCandidates = linkedWorktrees.filter((worktree) => worktree.path !== repository.currentRoot);
20
28
  const staleBaseRef = options.stale
21
- ? await resolveStaleBaseRef(repository.repoRoot, options.stderr)
29
+ ? await resolveStaleBaseRef(repository.repoRoot, options.stderr, loadEffectiveConfig, resolveRemoteDefaultBranch, runGit)
22
30
  : null;
23
31
  const cleanupCandidates = options.stale
24
- ? await filterStaleCleanupCandidates(repository.repoRoot, linkedCleanupCandidates, staleBaseRef)
32
+ ? await filterStaleCleanupCandidates(repository.repoRoot, linkedCleanupCandidates, staleBaseRef, readWorktreeHealth, isBranchMergedInto)
25
33
  : linkedCleanupCandidates;
26
34
  if (cleanupCandidates.length === 0) {
27
35
  if (options.stale) {
@@ -49,7 +57,7 @@ export function createCleanCommand(dependencies = {}) {
49
57
  : await promptForWorktrees(await buildWorktreePromptEntries(cleanupCandidates.map((worktree) => ({
50
58
  repoName: repository.repoName,
51
59
  worktree,
52
- }))));
60
+ })), { catalog: runtime.worktreeCatalog }));
53
61
  if (!selections || selections.length === 0) {
54
62
  options.stderr("Aborted\n");
55
63
  return 1;
@@ -74,7 +82,7 @@ export function createCleanCommand(dependencies = {}) {
74
82
  }
75
83
  else {
76
84
  for (const info of selectedWorktreeInfos) {
77
- options.stdout(`Would remove worktree at ${info.path} (${formatCleanInfo(info)})\n`);
85
+ options.stdout(`Would remove worktree at ${info.path} (${formatCleanInfo(info, formatLastCommit, formatUpstreamState)})\n`);
78
86
  }
79
87
  }
80
88
  return 0;
@@ -83,7 +91,7 @@ export function createCleanCommand(dependencies = {}) {
83
91
  const failures = [];
84
92
  let journal;
85
93
  try {
86
- journal = await recordUndoOperation("clean", repository.repoRoot, selectedWorktrees);
94
+ journal = await recordUndoOperation("clean", repository.repoRoot, selectedWorktrees, undefined, runtime);
87
95
  }
88
96
  catch (error) {
89
97
  emitError(options, `could not write undo journal; no worktrees were removed: ${toMessage(error)}`);
@@ -95,7 +103,7 @@ export function createCleanCommand(dependencies = {}) {
95
103
  }
96
104
  for (const worktree of selectedWorktrees) {
97
105
  if (options.stale &&
98
- !(await isStaleCleanupCandidate(repository.repoRoot, worktree, staleBaseRef))) {
106
+ !(await isStaleCleanupCandidate(repository.repoRoot, worktree, staleBaseRef, readWorktreeHealth, isBranchMergedInto))) {
99
107
  options.stderr(`Skipped ${worktree.path}: no longer a safe stale cleanup candidate\n`);
100
108
  continue;
101
109
  }
@@ -167,7 +175,7 @@ export function createCleanCommand(dependencies = {}) {
167
175
  }
168
176
  }
169
177
  }
170
- await finalizeUndoOperation(journal, removedWorktrees);
178
+ await finalizeUndoOperation(journal, removedWorktrees, undefined, runtime.configStore.GLOBAL_CONFIG_DIRECTORY);
171
179
  await Promise.all(removedWorktrees.map((worktree) => releaseWorktreeSlot(worktree.path)));
172
180
  if (options.json) {
173
181
  const removed = removedWorktrees.map((worktree) => {
@@ -190,31 +198,31 @@ export function createCleanCommand(dependencies = {}) {
190
198
  };
191
199
  }
192
200
  export const runCleanCommand = createCleanCommand();
193
- async function filterStaleCleanupCandidates(repoRoot, worktrees, baseBranch) {
201
+ async function filterStaleCleanupCandidates(repoRoot, worktrees, baseBranch, readWorktreeHealth, isBranchMergedInto) {
194
202
  if (baseBranch === null) {
195
203
  return [];
196
204
  }
197
- const results = await Promise.all(worktrees.map((worktree) => isStaleCleanupCandidate(repoRoot, worktree, baseBranch)));
205
+ const results = await Promise.all(worktrees.map((worktree) => isStaleCleanupCandidate(repoRoot, worktree, baseBranch, readWorktreeHealth, isBranchMergedInto)));
198
206
  return worktrees.filter((_, index) => results[index]);
199
207
  }
200
- async function resolveStaleBaseRef(repoRoot, stderr) {
208
+ async function resolveStaleBaseRef(repoRoot, stderr, loadEffectiveConfig, resolveRemoteDefaultBranch, runGit) {
201
209
  const config = await loadEffectiveConfig(repoRoot, undefined, stderr);
202
210
  const remote = resolveConfiguredString(config.syncRemote) ?? "origin";
203
211
  const configuredDefaultBranch = resolveConfiguredString(config.syncDefaultBranch);
204
212
  if (configuredDefaultBranch) {
205
- return await resolveFetchedRemoteRef(repoRoot, remote, configuredDefaultBranch);
213
+ return await resolveFetchedRemoteRef(repoRoot, remote, configuredDefaultBranch, runGit);
206
214
  }
207
215
  try {
208
216
  const remoteDefaultBranch = await resolveRemoteDefaultBranch(repoRoot, remote);
209
217
  return remoteDefaultBranch === null
210
218
  ? null
211
- : await resolveFetchedRemoteRef(repoRoot, remote, remoteDefaultBranch);
219
+ : await resolveFetchedRemoteRef(repoRoot, remote, remoteDefaultBranch, runGit);
212
220
  }
213
221
  catch {
214
222
  return null;
215
223
  }
216
224
  }
217
- async function resolveFetchedRemoteRef(repoRoot, remote, branch) {
225
+ async function resolveFetchedRemoteRef(repoRoot, remote, branch, runGit) {
218
226
  try {
219
227
  await runGit(repoRoot, ["fetch", "--prune", remote]);
220
228
  return `${remote}/${branch}`;
@@ -226,7 +234,7 @@ async function resolveFetchedRemoteRef(repoRoot, remote, branch) {
226
234
  function resolveConfiguredString(value) {
227
235
  return typeof value === "string" && value.length > 0 ? value : null;
228
236
  }
229
- async function isStaleCleanupCandidate(repoRoot, worktree, baseBranch) {
237
+ async function isStaleCleanupCandidate(repoRoot, worktree, baseBranch, readWorktreeHealth, isBranchMergedInto) {
230
238
  if (baseBranch === null) {
231
239
  return false;
232
240
  }
@@ -260,7 +268,7 @@ function reportCleanFailures(failures, stderr) {
260
268
  stderr(`- ${failure.path} (${branch}): ${failure.message}\n`);
261
269
  }
262
270
  }
263
- function formatCleanInfo(info) {
271
+ function formatCleanInfo(info, formatLastCommit, formatUpstreamState) {
264
272
  const branch = info.branch === null ? "detached" : `branch: ${info.branch}`;
265
273
  const status = `status: ${info.status}`;
266
274
  const upstream = `upstream: ${formatUpstreamState(info.upstream)}`;
@@ -1,5 +1,5 @@
1
- import { resolveSupportedShell } from "./shell.js";
2
- import { renderShellCompletion } from "./shell-completion.js";
1
+ import { renderShellCompletion } from "../../presentation/shell/completion.js";
2
+ import { resolveSupportedShell } from "../../presentation/shell/shell.js";
3
3
  export async function runCompletionCommand(options) {
4
4
  const shell = options.shell
5
5
  ? resolveSupportedShell(options.shell, undefined)
@@ -1,3 +1,4 @@
1
+ import { type CliRuntime } from "../dependencies.js";
1
2
  export interface ConfigCommandOptions {
2
3
  action?: string;
3
4
  cwd: string;
@@ -5,5 +6,6 @@ export interface ConfigCommandOptions {
5
6
  stderr?: (chunk: string) => void;
6
7
  stdout: (chunk: string) => void;
7
8
  value?: string;
9
+ runtime?: CliRuntime<"configStore">;
8
10
  }
9
11
  export declare function runConfigCommand(options: ConfigCommandOptions): Promise<number>;
@@ -1,20 +1,22 @@
1
- import { loadGlobalConfig, parseConfigValue, unsetGlobalConfigKey, updateGlobalConfigKey, } from "./config.js";
1
+ import { defaultCliDependencies } from "../dependencies.js";
2
2
  export async function runConfigCommand(options) {
3
+ const runtime = options.runtime ?? defaultCliDependencies;
4
+ const config = runtime.configStore;
3
5
  switch (options.action) {
4
6
  case undefined: {
5
- const loaded = await loadGlobalConfig();
7
+ const loaded = await config.loadGlobalConfig();
6
8
  writeJson(options.stdout, loaded.config);
7
9
  return 0;
8
10
  }
9
11
  case "get": {
10
- const loaded = await loadGlobalConfig();
12
+ const loaded = await config.loadGlobalConfig();
11
13
  writeJson(options.stdout, options.key ? loaded.config[options.key] : loaded.config);
12
14
  return 0;
13
15
  }
14
16
  case "set":
15
17
  if (options.key && options.value !== undefined) {
16
18
  try {
17
- await updateGlobalConfigKey(options.key, parseConfigValue(options.value));
19
+ await config.updateGlobalConfigKey(options.key, config.parseConfigValue(options.value));
18
20
  }
19
21
  catch (error) {
20
22
  options.stderr?.(`gji config: ${error instanceof Error ? error.message : String(error)}\n`);
@@ -25,7 +27,7 @@ export async function runConfigCommand(options) {
25
27
  break;
26
28
  case "unset":
27
29
  if (options.key) {
28
- await unsetGlobalConfigKey(options.key);
30
+ await config.unsetGlobalConfigKey(options.key);
29
31
  return 0;
30
32
  }
31
33
  break;
@@ -1,3 +1,4 @@
1
+ import { type CliRuntime } from "../dependencies.js";
1
2
  export type DoctorCheckStatus = "fail" | "ok" | "skip";
2
3
  export interface DoctorCheck {
3
4
  hint?: string;
@@ -22,6 +23,7 @@ export interface DoctorCommandOptions {
22
23
  confirmFixes?: (fixes: DoctorFix[]) => Promise<boolean>;
23
24
  shell?: string;
24
25
  yes?: boolean;
26
+ runtime?: CliRuntime<"integrations" | "slots" | "repositoryContext" | "configStore" | "registry">;
25
27
  stderr?: (chunk: string) => void;
26
28
  stdout: (chunk: string) => void;
27
29
  }
@@ -5,17 +5,14 @@ import { homedir } from "node:os";
5
5
  import { basename, dirname, join } from "node:path";
6
6
  import { promisify } from "node:util";
7
7
  import { confirm, isCancel } from "@clack/prompts";
8
- import { CONFIG_FILE_NAME, GLOBAL_CONFIG_FILE_PATH, KNOWN_CONFIG_KEYS, KNOWN_GLOBAL_CONFIG_KEYS, } from "./config.js";
9
- import { EDITORS } from "./editor.js";
10
- import { isHeadless } from "./headless.js";
11
- import { detectRepository } from "./repo.js";
12
- import { loadRegistry, REGISTRY_FILE_PATH, removeMissingRegistryEntries, } from "./repo-registry.js";
13
- import { resolveSupportedShell } from "./shell.js";
14
- import { executableExists, hasShellIntegration, resolveCompletionPath, resolveShellConfigPath, } from "./shell-setup.js";
15
- import { loadSlots } from "./slots.js";
8
+ import { executableExists, hasShellIntegration, resolveCompletionPath, resolveShellConfigPath, } from "../../presentation/shell/setup.js";
9
+ import { resolveSupportedShell, } from "../../presentation/shell/shell.js";
10
+ import { defaultCliDependencies, } from "../dependencies.js";
11
+ import { isHeadless } from "../runtime/headless.js";
16
12
  const execFileAsync = promisify(execFile);
17
13
  const MINIMUM_GIT_VERSION = { major: 2, minor: 17 };
18
14
  export async function runDoctorCommand(options) {
15
+ const runtime = options.runtime ?? defaultCliDependencies;
19
16
  if (options.yes && !options.fix) {
20
17
  const message = "--yes requires --fix";
21
18
  if (options.json) {
@@ -28,14 +25,14 @@ export async function runDoctorCommand(options) {
28
25
  }
29
26
  const home = options.home ?? homedir();
30
27
  const shell = resolveSupportedShell(undefined, options.shell ?? process.env.SHELL);
31
- let inspection = await collectDoctorInspection(options.cwd, home, shell);
28
+ let inspection = await collectDoctorInspection(options.cwd, home, shell, runtime);
32
29
  let fixes = [];
33
30
  if (options.fix) {
34
31
  fixes = buildDoctorFixes(inspection.missingRegistryPaths);
35
32
  if (fixes.length > 0) {
36
33
  const approval = await requestFixApproval(fixes, options);
37
34
  if (approval === "apply") {
38
- fixes = await applyDoctorFixes(fixes, home);
35
+ fixes = await applyDoctorFixes(fixes, home, runtime.registry);
39
36
  }
40
37
  else {
41
38
  fixes = fixes.map((fix) => ({
@@ -47,7 +44,7 @@ export async function runDoctorCommand(options) {
47
44
  }));
48
45
  }
49
46
  }
50
- inspection = await collectDoctorInspection(options.cwd, home, shell);
47
+ inspection = await collectDoctorInspection(options.cwd, home, shell, runtime);
51
48
  }
52
49
  const problems = inspection.checks.filter((check) => check.status === "fail").length;
53
50
  if (options.json) {
@@ -64,14 +61,15 @@ export async function runDoctorCommand(options) {
64
61
  }
65
62
  return problems > 0 ? 1 : 0;
66
63
  }
67
- async function collectDoctorInspection(cwd, home, shell) {
68
- const repository = await detectRepositoryOrSkip(cwd);
64
+ async function collectDoctorInspection(cwd, home, shell, runtime) {
65
+ const { CONFIG_FILE_NAME, GLOBAL_CONFIG_FILE_PATH, KNOWN_CONFIG_KEYS, KNOWN_GLOBAL_CONFIG_KEYS, } = runtime.configStore;
66
+ const repository = await detectRepositoryOrSkip(cwd, runtime.repositoryContext.detectRepository);
69
67
  const globalConfig = await inspectConfig(GLOBAL_CONFIG_FILE_PATH(home), "global", KNOWN_GLOBAL_CONFIG_KEYS);
70
68
  const localConfig = repository
71
69
  ? await inspectConfig(join(repository.repoRoot, CONFIG_FILE_NAME), "local", KNOWN_CONFIG_KEYS)
72
70
  : null;
73
71
  const effectiveConfig = resolveEffectiveConfig(globalConfig.config, localConfig?.config ?? {}, repository?.repoRoot, home);
74
- const registry = await inspectRegistry(home);
72
+ const registry = await inspectRegistry(home, runtime.registry);
75
73
  return {
76
74
  checks: [
77
75
  await checkGitVersion(),
@@ -82,13 +80,13 @@ async function collectDoctorInspection(cwd, home, shell) {
82
80
  skippedCheck("local-config", "local config not checked outside a Git repository"),
83
81
  await checkWorktreeBase(repository, effectiveConfig, home),
84
82
  registry.check,
85
- await checkEditor(effectiveConfig),
86
- await checkOrphanSlots(home),
83
+ await checkEditor(effectiveConfig, runtime.integrations.EDITORS),
84
+ await checkOrphanSlots(home, runtime.slots.loadSlots),
87
85
  ],
88
86
  missingRegistryPaths: registry.missingPaths,
89
87
  };
90
88
  }
91
- async function checkOrphanSlots(home) {
89
+ async function checkOrphanSlots(home, loadSlots) {
92
90
  const slots = await loadSlots(home);
93
91
  const missing = (await Promise.all(Object.keys(slots).map(async (path) => {
94
92
  try {
@@ -142,10 +140,10 @@ function isDoctorInteractive(options) {
142
140
  return options.interactive;
143
141
  return process.stdin.isTTY === true && process.stdout.isTTY === true;
144
142
  }
145
- async function applyDoctorFixes(fixes, home) {
143
+ async function applyDoctorFixes(fixes, home, registry) {
146
144
  return Promise.all(fixes.map(async (fix) => {
147
145
  try {
148
- const result = await removeMissingRegistryEntries(new Set(fix.paths ?? []), home);
146
+ const result = await registry.removeMissingRegistryEntries(new Set(fix.paths ?? []), home);
149
147
  const removedCount = result.removedPaths.length;
150
148
  const skippedCount = result.skippedPaths.length;
151
149
  return {
@@ -168,7 +166,7 @@ async function applyDoctorFixes(fixes, home) {
168
166
  }
169
167
  }));
170
168
  }
171
- async function detectRepositoryOrSkip(cwd) {
169
+ async function detectRepositoryOrSkip(cwd, detectRepository) {
172
170
  try {
173
171
  return await detectRepository(cwd);
174
172
  }
@@ -342,8 +340,8 @@ async function findNearestExistingPath(path) {
342
340
  }
343
341
  }
344
342
  }
345
- async function inspectRegistry(home) {
346
- const entries = await loadRegistry(home);
343
+ async function inspectRegistry(home, registry) {
344
+ const entries = await registry.loadRegistry(home);
347
345
  const missingEntries = await Promise.all(entries.map(async (entry) => ({
348
346
  entry,
349
347
  status: await inspectRegistryPath(entry.path),
@@ -368,7 +366,7 @@ async function inspectRegistry(home) {
368
366
  }
369
367
  return {
370
368
  check: failedCheck("repo-registry", `${entries.length} repos registered, ${messageParts.join(", ")}`, missingCount > 0
371
- ? `remove confirmed stale entries from ${REGISTRY_FILE_PATH(home)}; check permissions for inaccessible paths`
369
+ ? `remove confirmed stale entries from ${registry.REGISTRY_FILE_PATH(home)}; check permissions for inaccessible paths`
372
370
  : "check permissions for inaccessible paths before removing registry entries"),
373
371
  missingPaths,
374
372
  };
@@ -399,7 +397,7 @@ async function pathExists(path) {
399
397
  return false;
400
398
  }
401
399
  }
402
- async function checkEditor(config) {
400
+ async function checkEditor(config, editors) {
403
401
  const editor = config.editor;
404
402
  if (typeof editor !== "string" || editor.length === 0) {
405
403
  return skippedCheck("editor", "editor not configured (optional)");
@@ -407,7 +405,7 @@ async function checkEditor(config) {
407
405
  if (await executableExists(editor)) {
408
406
  return okCheck("editor", `editor "${editor}" found on PATH`);
409
407
  }
410
- const knownEditor = EDITORS.some(({ cli }) => cli === editor);
408
+ const knownEditor = editors.some(({ cli }) => cli === editor);
411
409
  return failedCheck("editor", `editor "${editor}" was not found on PATH`, knownEditor
412
410
  ? `install ${editor} or choose another editor with: gji open --save`
413
411
  : "choose another editor with: gji open --save");
@@ -1,9 +1,11 @@
1
+ import { type CliRuntime } from "../dependencies.js";
1
2
  export interface DoneCommandOptions {
2
3
  branch?: string;
3
4
  cwd: string;
4
5
  force?: boolean;
5
6
  json?: boolean;
6
7
  keepBranch?: boolean;
8
+ runtime?: CliRuntime<"git" | "config" | "configStore" | "historyStore" | "slots" | "hooks" | "repositoryContext" | "worktrees" | "worktreeLifecycle">;
7
9
  stderr: (chunk: string) => void;
8
10
  stdout: (chunk: string) => void;
9
11
  }
@@ -1,17 +1,20 @@
1
1
  import { basename } from "node:path";
2
2
  import { confirm, isCancel } from "@clack/prompts";
3
- import { loadEffectiveConfig, resolveConfigString } from "./config.js";
4
- import { isBranchMergedInto, readWorktreeHealth, resolveRemoteDefaultBranch, runGit, } from "./git.js";
5
- import { isHeadless } from "./headless.js";
6
- import { loadHistory } from "./history.js";
7
- import { extractHooks, runHook } from "./hooks.js";
8
- import { detectRepository, listWorktrees } from "./repo.js";
9
- import { writeShellOutput } from "./shell-handoff.js";
10
- import { releaseWorktreeSlot } from "./slots.js";
3
+ import { writeShellOutput } from "../../presentation/shell/handoff.js";
4
+ import { defaultCliDependencies, } from "../dependencies.js";
5
+ import { isHeadless } from "../runtime/headless.js";
11
6
  import { finalizeUndoOperation, recordUndoOperation } from "./undo.js";
12
- import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isWorktreeForceRemovalError, removeWorktree, } from "./worktree-management.js";
13
7
  const DONE_OUTPUT_FILE_ENV = "GJI_DONE_OUTPUT_FILE";
14
8
  export async function runDoneCommand(options) {
9
+ const runtime = options.runtime ?? defaultCliDependencies;
10
+ const { readWorktreeHealth, isBranchMergedInto, resolveRemoteDefaultBranch, runGit, } = runtime.git;
11
+ const { loadEffectiveConfig, resolveConfigString } = runtime.config;
12
+ const { loadHistory } = runtime.historyStore;
13
+ const { releaseWorktreeSlot } = runtime.slots;
14
+ const { extractHooks, runHook } = runtime.hooks;
15
+ const { detectRepository } = runtime.repositoryContext;
16
+ const { listWorktrees } = runtime.worktrees;
17
+ const { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isWorktreeForceRemovalError, removeWorktree, } = runtime.worktreeLifecycle;
15
18
  const repository = await detectRepository(options.cwd);
16
19
  if (!repository.isWorktree && !options.branch)
17
20
  return doneError(options, "gji done: not inside a linked worktree");
@@ -24,12 +27,12 @@ export async function runDoneCommand(options) {
24
27
  ? `gji done: no linked worktree found for ${options.branch}`
25
28
  : "gji done: not inside a linked worktree");
26
29
  const config = await loadEffectiveConfig(repository.repoRoot, undefined, options.stderr);
27
- await refreshUpstream(repository.repoRoot, target.path);
30
+ await refreshUpstream(repository.repoRoot, target.path, runGit);
28
31
  const health = await readWorktreeHealth(target.path);
29
32
  if (target.branch &&
30
33
  !options.force &&
31
34
  !options.keepBranch &&
32
- !(await isSafeToComplete(repository.repoRoot, target.branch, health, config))) {
35
+ !(await isSafeToComplete(repository.repoRoot, target.branch, health, config, resolveConfigString, resolveRemoteDefaultBranch, isBranchMergedInto, runGit))) {
33
36
  if (options.json || isHeadless())
34
37
  return doneError(options, "branch is not merged and its upstream is not gone; use --force");
35
38
  const choice = await confirm({
@@ -55,7 +58,7 @@ export async function runDoneCommand(options) {
55
58
  }
56
59
  let journal;
57
60
  try {
58
- journal = await recordUndoOperation("done", repository.repoRoot, [target]);
61
+ journal = await recordUndoOperation("done", repository.repoRoot, [target], undefined, runtime);
59
62
  }
60
63
  catch (error) {
61
64
  return doneError(options, `could not write undo journal; no worktree was removed: ${toMessage(error)}`);
@@ -72,12 +75,12 @@ export async function runDoneCommand(options) {
72
75
  }
73
76
  catch (error) {
74
77
  if (!isWorktreeForceRemovalError(error)) {
75
- await finalizeUndoOperation(journal, []);
78
+ await finalizeUndoOperation(journal, [], undefined, runtime.configStore.GLOBAL_CONFIG_DIRECTORY);
76
79
  return doneError(options, `Failed to remove worktree at ${target.path}: ${toMessage(error)}`);
77
80
  }
78
81
  if (!options.force) {
79
82
  if (options.json || isHeadless()) {
80
- await finalizeUndoOperation(journal, []);
83
+ await finalizeUndoOperation(journal, [], undefined, runtime.configStore.GLOBAL_CONFIG_DIRECTORY);
81
84
  return doneError(options, "worktree requires force removal; use --force");
82
85
  }
83
86
  const choice = await confirm({
@@ -87,7 +90,7 @@ export async function runDoneCommand(options) {
87
90
  initialValue: false,
88
91
  });
89
92
  if (isCancel(choice) || !choice) {
90
- await finalizeUndoOperation(journal, []);
93
+ await finalizeUndoOperation(journal, [], undefined, runtime.configStore.GLOBAL_CONFIG_DIRECTORY);
91
94
  return doneError(options, "Aborted");
92
95
  }
93
96
  }
@@ -95,7 +98,7 @@ export async function runDoneCommand(options) {
95
98
  await forceRemoveWorktree(repository.repoRoot, target.path);
96
99
  }
97
100
  catch (forceError) {
98
- await finalizeUndoOperation(journal, []);
101
+ await finalizeUndoOperation(journal, [], undefined, runtime.configStore.GLOBAL_CONFIG_DIRECTORY);
99
102
  return doneError(options, `Failed to remove worktree at ${target.path}: ${toMessage(forceError)}`);
100
103
  }
101
104
  }
@@ -122,12 +125,12 @@ export async function runDoneCommand(options) {
122
125
  }
123
126
  }
124
127
  }
125
- await finalizeUndoOperation(journal, [target]);
128
+ await finalizeUndoOperation(journal, [target], undefined, runtime.configStore.GLOBAL_CONFIG_DIRECTORY);
126
129
  await releaseWorktreeSlot(target.path);
127
130
  await runGit(repository.repoRoot, ["worktree", "prune"]).catch(() => undefined);
128
131
  const shouldMove = options.branch === undefined || target.path === repository.currentRoot;
129
132
  const movedTo = shouldMove
130
- ? await resolveDoneDestination(repository.repoRoot, target.path)
133
+ ? await resolveDoneDestination(repository.repoRoot, target.path, loadHistory, runGit)
131
134
  : null;
132
135
  if (!options.json && movedTo)
133
136
  await writeShellOutput(DONE_OUTPUT_FILE_ENV, movedTo, options.stdout);
@@ -139,7 +142,7 @@ export async function runDoneCommand(options) {
139
142
  options.stderr(`✓ removed ${target.branch ?? "detached worktree"} (worktree${branchDeleted ? " + branch" : ""})${movedTo ? ` → back at ${movedTo}` : ""} · undo: gji undo\n`);
140
143
  return 0;
141
144
  }
142
- async function isSafeToComplete(repoRoot, branch, health, config) {
145
+ async function isSafeToComplete(repoRoot, branch, health, config, resolveConfigString, resolveRemoteDefaultBranch, isBranchMergedInto, runGit) {
143
146
  if (health.upstreamGone)
144
147
  return true;
145
148
  const remote = resolveConfigString(config, "syncRemote") ?? "origin";
@@ -148,7 +151,7 @@ async function isSafeToComplete(repoRoot, branch, health, config) {
148
151
  (await resolveRemoteDefaultBranch(repoRoot, remote).catch(() => null));
149
152
  if (remoteDefault) {
150
153
  for (const base of [`${remote}/${remoteDefault}`, remoteDefault]) {
151
- if (await gitRefExists(repoRoot, base))
154
+ if (await gitRefExists(repoRoot, base, runGit))
152
155
  return isBranchMergedInto(repoRoot, branch, base).catch(() => false);
153
156
  }
154
157
  return false;
@@ -162,7 +165,7 @@ async function isSafeToComplete(repoRoot, branch, health, config) {
162
165
  ? false
163
166
  : isBranchMergedInto(repoRoot, branch, base).catch(() => false);
164
167
  }
165
- async function gitRefExists(repoRoot, ref) {
168
+ async function gitRefExists(repoRoot, ref, runGit) {
166
169
  try {
167
170
  await runGit(repoRoot, ["rev-parse", "--verify", ref]);
168
171
  return true;
@@ -171,7 +174,7 @@ async function gitRefExists(repoRoot, ref) {
171
174
  return false;
172
175
  }
173
176
  }
174
- async function refreshUpstream(repoRoot, worktreePath) {
177
+ async function refreshUpstream(repoRoot, worktreePath, runGit) {
175
178
  const upstream = await runGit(worktreePath, [
176
179
  "rev-parse",
177
180
  "--abbrev-ref",
@@ -183,7 +186,7 @@ async function refreshUpstream(repoRoot, worktreePath) {
183
186
  return;
184
187
  await runGit(repoRoot, ["fetch", "--prune", "--quiet", remote]).catch(() => undefined);
185
188
  }
186
- async function resolveDoneDestination(repoRoot, removedPath) {
189
+ async function resolveDoneDestination(repoRoot, removedPath, loadHistory, runGit) {
187
190
  const history = await loadHistory();
188
191
  for (const entry of history) {
189
192
  if (entry.path !== removedPath && entry.path !== repoRoot) {
@@ -1,4 +1,5 @@
1
- import { type QueryWorktreePullRequests, type WorktreePromptEntry, type WorktreePromptScope } from "./worktree-picker.js";
1
+ import { type QueryWorktreePullRequests, type WorktreePromptEntry, type WorktreePromptScope } from "../../presentation/worktree/picker.js";
2
+ import { type CliRuntime } from "../dependencies.js";
2
3
  export interface GoCommandOptions {
3
4
  branch?: string;
4
5
  cwd: string;
@@ -8,11 +9,15 @@ export interface GoCommandOptions {
8
9
  quiet?: boolean;
9
10
  stderr: (chunk: string) => void;
10
11
  stdout: (chunk: string) => void;
12
+ runtime?: GoRuntime;
11
13
  }
14
+ type GoRuntime = CliRuntime<"bootstrap" | "config" | "contextCard" | "git" | "history" | "historyStore" | "hooks" | "integrations" | "repositoryContext" | "repositoryRefs" | "repositoryRegistry" | "slots" | "tasks" | "worktrees" | "worktreeCatalog">;
12
15
  export interface GoCommandDependencies {
13
16
  confirmBranchCreation: (branch: string) => Promise<boolean>;
14
17
  promptForWorktree: (worktrees: WorktreePromptEntry[], scope?: WorktreePromptScope) => Promise<string | null>;
15
18
  queryPullRequests: QueryWorktreePullRequests;
19
+ runtime: GoRuntime;
16
20
  }
17
21
  export declare function createGoCommand(dependencies?: Partial<GoCommandDependencies>): (options: GoCommandOptions) => Promise<number>;
18
22
  export declare const runGoCommand: (options: GoCommandOptions) => Promise<number>;
23
+ export {};