@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
package/dist/repo.js DELETED
@@ -1,161 +0,0 @@
1
- import { access } from "node:fs/promises";
2
- import { homedir } from "node:os";
3
- import { basename, dirname, isAbsolute, join, resolve } from "node:path";
4
- import { runGit } from "./git.js";
5
- export async function detectRepository(cwd) {
6
- const currentRoot = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
7
- const rawCommonDir = await runGit(cwd, ["rev-parse", "--git-common-dir"]);
8
- const gitCommonDir = isAbsolute(rawCommonDir)
9
- ? rawCommonDir
10
- : resolve(currentRoot, rawCommonDir);
11
- const repoRoot = dirname(gitCommonDir);
12
- return {
13
- currentRoot,
14
- gitCommonDir,
15
- isWorktree: currentRoot !== repoRoot,
16
- repoName: basename(repoRoot),
17
- repoRoot,
18
- };
19
- }
20
- export async function worktreeGitDir(worktreePath) {
21
- const rawGitDir = await runGit(worktreePath, ["rev-parse", "--git-dir"]);
22
- return isAbsolute(rawGitDir) ? rawGitDir : resolve(worktreePath, rawGitDir);
23
- }
24
- export function resolveWorktreePath(repoRoot, branch, basePath) {
25
- const segments = branch.split("/").filter(Boolean);
26
- if (segments.length === 0) {
27
- throw new Error("Branch name must not be empty.");
28
- }
29
- if (segments.some((segment) => segment === "." || segment === "..")) {
30
- throw new Error(`Branch name '${branch}' contains an invalid path segment.`);
31
- }
32
- const base = basePath
33
- ? expandTildeInPath(basePath)
34
- : join(dirname(repoRoot), "worktrees", basename(repoRoot));
35
- return join(base, ...segments);
36
- }
37
- export function validateBranchName(name) {
38
- if (name.length === 0) {
39
- return "Branch name must not be empty.";
40
- }
41
- // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional control chars to reject in git branch names
42
- if (/[\x00-\x1f\x7f ~^:?*[\\\s]/.test(name)) {
43
- return `Branch name '${name}' contains an invalid character.`;
44
- }
45
- if (name.startsWith("-")) {
46
- return `Branch name '${name}' must not start with a dash.`;
47
- }
48
- if (name.startsWith("/") || name.endsWith("/") || name.includes("//")) {
49
- return `Branch name '${name}' has invalid slash placement.`;
50
- }
51
- if (name.includes("..")) {
52
- return `Branch name '${name}' must not contain '..'.`;
53
- }
54
- if (name.endsWith(".")) {
55
- return `Branch name '${name}' must not end with '.'.`;
56
- }
57
- if (name.includes("@{")) {
58
- return `Branch name '${name}' must not contain '@{'.`;
59
- }
60
- if (name === "@") {
61
- return "Branch name cannot be '@'.";
62
- }
63
- for (const segment of name.split("/")) {
64
- if (segment.startsWith(".")) {
65
- return `Branch name '${name}' contains a path component starting with '.'.`;
66
- }
67
- if (segment.endsWith(".lock")) {
68
- return `Branch name '${name}' contains a path component ending with '.lock'.`;
69
- }
70
- }
71
- return null;
72
- }
73
- export async function hasLocalBranch(repoRoot, branch) {
74
- try {
75
- await runGit(repoRoot, [
76
- "show-ref",
77
- "--verify",
78
- "--quiet",
79
- `refs/heads/${branch}`,
80
- ]);
81
- return true;
82
- }
83
- catch {
84
- return false;
85
- }
86
- }
87
- export async function hasRemoteBranch(repoRoot, remote, branch) {
88
- try {
89
- await runGit(repoRoot, [
90
- "show-ref",
91
- "--verify",
92
- "--quiet",
93
- `refs/remotes/${remote}/${branch}`,
94
- ]);
95
- return true;
96
- }
97
- catch {
98
- return false;
99
- }
100
- }
101
- export async function getRepositoryRemoteUrl(repoRoot, remote) {
102
- try {
103
- return await runGit(repoRoot, ["remote", "get-url", remote]);
104
- }
105
- catch {
106
- return null;
107
- }
108
- }
109
- function expandTildeInPath(p) {
110
- if (p === "~")
111
- return homedir();
112
- if (p.startsWith("~/"))
113
- return join(homedir(), p.slice(2));
114
- return p;
115
- }
116
- export async function listWorktrees(cwd) {
117
- const [output, currentRoot] = await Promise.all([
118
- runGit(cwd, ["worktree", "list", "--porcelain"]),
119
- runGit(cwd, ["rev-parse", "--show-toplevel"]),
120
- ]);
121
- const entries = output.split("\n\n").filter(Boolean);
122
- const worktrees = entries.flatMap((entry) => {
123
- if (findOptionalPorcelainValue(entry, "prunable") !== null)
124
- return [];
125
- const path = findPorcelainValue(entry, "worktree");
126
- const branchRef = findOptionalPorcelainValue(entry, "branch");
127
- return [
128
- {
129
- branch: branchRef ? branchRef.replace("refs/heads/", "") : null,
130
- isCurrent: path === currentRoot,
131
- path,
132
- },
133
- ];
134
- });
135
- const accessible = await Promise.all(worktrees.map(async (worktree) => {
136
- try {
137
- await access(worktree.path);
138
- return worktree;
139
- }
140
- catch {
141
- return null;
142
- }
143
- }));
144
- return accessible.filter((worktree) => worktree !== null);
145
- }
146
- function findPorcelainValue(block, key) {
147
- const value = findOptionalPorcelainValue(block, key);
148
- if (!value) {
149
- throw new Error(`Missing '${key}' in git worktree output.`);
150
- }
151
- return value;
152
- }
153
- function findOptionalPorcelainValue(block, key) {
154
- const line = block
155
- .split("\n")
156
- .find((candidate) => candidate.startsWith(`${key} `));
157
- if (!line) {
158
- return null;
159
- }
160
- return line.slice(key.length + 1);
161
- }
@@ -1,24 +0,0 @@
1
- import type { EffectiveGjiConfig } from "./config.js";
2
- import { type BootstrapCommandRunner, type BootstrapEvent, type DependencyBootstrapMode, type DependencyBootstrapReport, type DependencyBootstrapReporter } from "./dependency-bootstrap.js";
3
- export interface WorktreeBootstrapOptions {
4
- branch: string;
5
- config: EffectiveGjiConfig;
6
- currentRoot?: string;
7
- dependencyDetectionRoot?: string;
8
- dependencyMode: DependencyBootstrapMode;
9
- runCommand?: BootstrapCommandRunner;
10
- commandStdout?: (chunk: string) => void;
11
- commandStderr?: (chunk: string) => void;
12
- json?: boolean;
13
- repoRoot: string;
14
- reporter: DependencyBootstrapReporter & {
15
- write: (chunk: string) => void;
16
- };
17
- worktreePath: string;
18
- }
19
- export interface WorktreeBootstrapResult {
20
- dependencyBootstrap: DependencyBootstrapReport;
21
- ready: boolean;
22
- syncFileFailures: readonly BootstrapEvent[];
23
- }
24
- export declare function bootstrapWorktree(options: WorktreeBootstrapOptions): Promise<WorktreeBootstrapResult>;
@@ -1,37 +0,0 @@
1
- import { type WorktreeHealth } from "./git.js";
2
- import type { WorktreeEntry } from "./repo.js";
3
- export interface WorktreeInfo extends WorktreeEntry {
4
- lastCommitTimestamp: number | null;
5
- slot: number | null;
6
- status: WorktreeHealth["status"] | "unknown";
7
- task: string | null;
8
- upstream: UpstreamState;
9
- }
10
- export interface SerializedWorktreeInfo {
11
- branch: string | null;
12
- lastCommitTimestamp: number | null;
13
- path: string;
14
- slot: number | null;
15
- status: WorktreeInfo["status"];
16
- task: string | null;
17
- upstream: UpstreamState;
18
- }
19
- export type UpstreamState = {
20
- kind: "detached";
21
- } | {
22
- kind: "no-upstream";
23
- } | {
24
- kind: "stale";
25
- } | {
26
- kind: "tracked";
27
- ahead: number;
28
- behind: number;
29
- } | {
30
- kind: "unknown";
31
- };
32
- export declare function readWorktreeInfos(worktrees: WorktreeEntry[]): Promise<WorktreeInfo[]>;
33
- export declare function readWorktreeInfo(worktree: WorktreeEntry): Promise<WorktreeInfo>;
34
- export declare function serializeWorktreeInfo(info: WorktreeInfo): SerializedWorktreeInfo;
35
- export declare function formatUpstreamState(upstream: UpstreamState): string;
36
- export declare function formatLastCommit(timestampSeconds: number | null): string;
37
- export declare function formatRelativeAge(timestampSeconds: number, nowSeconds?: number): string;
@@ -1,123 +0,0 @@
1
- import { readBranchLastCommitTimestamp, readWorktreeHealth, } from "./git.js";
2
- import { getWorktreeSlot } from "./slots.js";
3
- import { readTask } from "./task.js";
4
- const MAX_WORKTREE_INFO_READ_CONCURRENCY = 8;
5
- export async function readWorktreeInfos(worktrees) {
6
- return mapWithConcurrency(worktrees, MAX_WORKTREE_INFO_READ_CONCURRENCY, readWorktreeInfo);
7
- }
8
- async function mapWithConcurrency(items, limit, mapper) {
9
- const results = new Array(items.length);
10
- let nextIndex = 0;
11
- async function readNext() {
12
- for (;;) {
13
- const index = nextIndex;
14
- nextIndex += 1;
15
- if (index >= items.length)
16
- return;
17
- results[index] = await mapper(items[index]);
18
- }
19
- }
20
- await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => readNext()));
21
- return results;
22
- }
23
- export async function readWorktreeInfo(worktree) {
24
- const [healthResult, lastCommitResult, slotResult, taskResult] = await Promise.allSettled([
25
- readWorktreeHealth(worktree.path),
26
- worktree.branch === null
27
- ? null
28
- : readBranchLastCommitTimestamp(worktree.path, worktree.branch),
29
- getWorktreeSlot(worktree.path),
30
- readTask(worktree.path),
31
- ]);
32
- const health = healthResult.status === "fulfilled" ? healthResult.value : null;
33
- const lastCommitTimestamp = lastCommitResult.status === "fulfilled" ? lastCommitResult.value : null;
34
- const slot = slotResult.status === "fulfilled" ? slotResult.value : null;
35
- const task = taskResult.status === "fulfilled" ? (taskResult.value?.task ?? null) : null;
36
- return {
37
- ...worktree,
38
- lastCommitTimestamp,
39
- slot,
40
- status: health?.status ?? "unknown",
41
- task,
42
- upstream: buildUpstreamState(worktree.branch, health),
43
- };
44
- }
45
- function buildUpstreamState(branch, health) {
46
- if (branch === null) {
47
- return { kind: "detached" };
48
- }
49
- if (health === null) {
50
- return { kind: "unknown" };
51
- }
52
- if (!health.hasUpstream) {
53
- return { kind: "no-upstream" };
54
- }
55
- if (health.upstreamGone) {
56
- return { kind: "stale" };
57
- }
58
- return {
59
- ahead: health.ahead,
60
- behind: health.behind,
61
- kind: "tracked",
62
- };
63
- }
64
- export function serializeWorktreeInfo(info) {
65
- return {
66
- branch: info.branch,
67
- lastCommitTimestamp: info.lastCommitTimestamp,
68
- path: info.path,
69
- slot: info.slot,
70
- status: info.status,
71
- task: info.task,
72
- upstream: info.upstream,
73
- };
74
- }
75
- export function formatUpstreamState(upstream) {
76
- if (upstream.kind === "detached") {
77
- return "n/a";
78
- }
79
- if (upstream.kind === "no-upstream") {
80
- return "no-upstream";
81
- }
82
- if (upstream.kind === "stale") {
83
- return "gone";
84
- }
85
- if (upstream.kind === "unknown") {
86
- return "unknown";
87
- }
88
- return formatAheadBehind(upstream.ahead, upstream.behind);
89
- }
90
- function formatAheadBehind(ahead, behind) {
91
- if (ahead === 0 && behind === 0) {
92
- return "up to date";
93
- }
94
- if (ahead === 0) {
95
- return `behind ${behind}`;
96
- }
97
- if (behind === 0) {
98
- return `ahead ${ahead}`;
99
- }
100
- return `ahead ${ahead}, behind ${behind}`;
101
- }
102
- export function formatLastCommit(timestampSeconds) {
103
- return timestampSeconds === null
104
- ? "n/a"
105
- : formatRelativeAge(timestampSeconds);
106
- }
107
- export function formatRelativeAge(timestampSeconds, nowSeconds = Math.floor(Date.now() / 1000)) {
108
- const ageSeconds = Math.max(0, nowSeconds - timestampSeconds);
109
- const units = [
110
- { label: "y", seconds: 365 * 24 * 60 * 60 },
111
- { label: "mo", seconds: 30 * 24 * 60 * 60 },
112
- { label: "d", seconds: 24 * 60 * 60 },
113
- { label: "h", seconds: 60 * 60 },
114
- { label: "m", seconds: 60 },
115
- ];
116
- for (const unit of units) {
117
- const value = Math.floor(ageSeconds / unit.seconds);
118
- if (value > 0) {
119
- return `${value}${unit.label} ago`;
120
- }
121
- }
122
- return "just now";
123
- }
@@ -1,4 +0,0 @@
1
- import { type RepoRegistryEntry } from "./repo-registry.js";
2
- import type { WorktreeSource } from "./worktree-source.js";
3
- export declare function listRegisteredWorktreeSources(cwd: string, onSkipped?: (entry: RepoRegistryEntry) => void): Promise<WorktreeSource[]>;
4
- export declare function listDiscoverableWorktreeSources(cwd: string, onSkipped?: (entry: RepoRegistryEntry) => void): Promise<WorktreeSource[]>;
File without changes
File without changes
File without changes
File without changes