@solaqua/gji 0.12.5 → 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.
- package/README.md +12 -0
- package/dist/application/worktree/catalog.d.ts +31 -0
- package/dist/application/worktree/catalog.js +88 -0
- package/dist/application/worktree/context-card.d.ts +14 -0
- package/dist/application/worktree/context-card.js +12 -0
- package/dist/{go-resolver.d.ts → application/worktree/go-resolution.d.ts} +12 -4
- package/dist/{go-resolver.js → application/worktree/go-resolution.js} +46 -44
- package/dist/application/worktree/read-models.d.ts +31 -0
- package/dist/application/worktree/sources.d.ts +7 -0
- package/dist/{worktree-sources.js → application/worktree/sources.js} +12 -24
- package/dist/{back.d.ts → cli/commands/back.d.ts} +3 -1
- package/dist/{back.js → cli/commands/back.js} +8 -6
- package/dist/{clean.d.ts → cli/commands/clean.d.ts} +4 -2
- package/dist/{clean.js → cli/commands/clean.js} +32 -24
- package/dist/{completion.js → cli/commands/completion.js} +2 -2
- package/dist/{config-command.d.ts → cli/commands/config-command.d.ts} +2 -0
- package/dist/{config-command.js → cli/commands/config-command.js} +7 -5
- package/dist/{doctor.d.ts → cli/commands/doctor.d.ts} +2 -0
- package/dist/{doctor.js → cli/commands/doctor.js} +23 -25
- package/dist/{done.d.ts → cli/commands/done.d.ts} +2 -0
- package/dist/{done.js → cli/commands/done.js} +26 -23
- package/dist/{go.d.ts → cli/commands/go.d.ts} +6 -1
- package/dist/{go.js → cli/commands/go.js} +57 -41
- package/dist/{history-command.d.ts → cli/commands/history-command.d.ts} +2 -0
- package/dist/{history-command.js → cli/commands/history-command.js} +3 -1
- package/dist/{hub.d.ts → cli/commands/hub.d.ts} +7 -3
- package/dist/{hub.js → cli/commands/hub.js} +23 -33
- package/dist/{init.d.ts → cli/commands/init.d.ts} +3 -1
- package/dist/{init.js → cli/commands/init.js} +37 -34
- package/dist/{ls.d.ts → cli/commands/ls.d.ts} +4 -2
- package/dist/{ls.js → cli/commands/ls.js} +8 -5
- package/dist/{new.d.ts → cli/commands/new.d.ts} +6 -2
- package/dist/{new.js → cli/commands/new.js} +237 -109
- package/dist/{open.d.ts → cli/commands/open.d.ts} +4 -2
- package/dist/{open.js → cli/commands/open.js} +19 -12
- package/dist/{pr-open.d.ts → cli/commands/pr-open.d.ts} +4 -2
- package/dist/{pr-open.js → cli/commands/pr-open.js} +20 -18
- package/dist/{pr.d.ts → cli/commands/pr.d.ts} +5 -3
- package/dist/{pr.js → cli/commands/pr.js} +34 -41
- package/dist/{remove.d.ts → cli/commands/remove.d.ts} +4 -2
- package/dist/{remove.js → cli/commands/remove.js} +23 -17
- package/dist/{root.d.ts → cli/commands/root.d.ts} +2 -0
- package/dist/{root.js → cli/commands/root.js} +4 -2
- package/dist/{run-hook.d.ts → cli/commands/run-hook.d.ts} +2 -0
- package/dist/{run-hook.js → cli/commands/run-hook.js} +7 -4
- package/dist/{status.d.ts → cli/commands/status.d.ts} +2 -0
- package/dist/{status.js → cli/commands/status.js} +10 -7
- package/dist/{sync-files-command.d.ts → cli/commands/sync-files-command.d.ts} +2 -0
- package/dist/{sync-files-command.js → cli/commands/sync-files-command.js} +11 -9
- package/dist/{sync.d.ts → cli/commands/sync.d.ts} +2 -0
- package/dist/{sync.js → cli/commands/sync.js} +7 -4
- package/dist/{task-command.d.ts → cli/commands/task-command.d.ts} +2 -0
- package/dist/{task-command.js → cli/commands/task-command.js} +4 -2
- package/dist/{undo.d.ts → cli/commands/undo.d.ts} +8 -6
- package/dist/{undo.js → cli/commands/undo.js} +44 -34
- package/dist/{warp.d.ts → cli/commands/warp.d.ts} +5 -2
- package/dist/{warp.js → cli/commands/warp.js} +20 -10
- package/dist/cli/dependencies.d.ts +114 -0
- package/dist/cli/dependencies.js +118 -0
- package/dist/{cli.d.ts → cli/program.d.ts} +4 -2
- package/dist/{cli.js → cli/program.js} +108 -124
- package/dist/domain/repository/context.d.ts +6 -0
- package/dist/domain/repository/context.js +1 -0
- package/dist/domain/repository/registry.d.ts +5 -0
- package/dist/domain/repository/registry.js +1 -0
- package/dist/domain/shared/concurrency.d.ts +1 -0
- package/dist/domain/shared/concurrency.js +15 -0
- package/dist/domain/worktree/matching.d.ts +4 -0
- package/dist/domain/worktree/matching.js +79 -0
- package/dist/domain/worktree/policy.d.ts +2 -0
- package/dist/domain/worktree/policy.js +58 -0
- package/dist/domain/worktree/pr-reference.d.ts +1 -0
- package/dist/domain/worktree/pr-reference.js +9 -0
- package/dist/{worktree-source.d.ts → domain/worktree/source.d.ts} +1 -1
- package/dist/domain/worktree/source.js +1 -0
- package/dist/domain/worktree/types.d.ts +5 -0
- package/dist/domain/worktree/types.js +1 -0
- package/dist/gji-bundle.mjs +7035 -6212
- package/dist/index.js +3 -3
- package/dist/{dependency-bootstrap.d.ts → infrastructure/bootstrap/dependency-bootstrap.d.ts} +3 -30
- package/dist/{dependency-bootstrap.js → infrastructure/bootstrap/dependency-bootstrap.js} +4 -4
- package/dist/infrastructure/git/health.d.ts +9 -0
- package/dist/infrastructure/git/health.js +44 -0
- package/dist/infrastructure/git/refs.d.ts +6 -0
- package/dist/{git.js → infrastructure/git/refs.js} +1 -51
- package/dist/infrastructure/git/runner.d.ts +2 -0
- package/dist/infrastructure/git/runner.js +16 -0
- package/dist/{editor.d.ts → infrastructure/integrations/editor.d.ts} +2 -6
- package/dist/{pull-requests.d.ts → infrastructure/integrations/pull-requests.d.ts} +3 -11
- package/dist/{config.d.ts → infrastructure/persistence/config.d.ts} +3 -17
- package/dist/{config.js → infrastructure/persistence/config.js} +2 -17
- package/dist/{history.d.ts → infrastructure/persistence/history.d.ts} +2 -5
- package/dist/{task.js → infrastructure/persistence/task.js} +1 -1
- package/dist/infrastructure/process/command-runner.d.ts +3 -0
- package/dist/{hooks.d.ts → infrastructure/process/hooks.d.ts} +2 -12
- package/dist/infrastructure/repository/adapters.d.ts +7 -0
- package/dist/infrastructure/repository/adapters.js +23 -0
- package/dist/infrastructure/repository/context.d.ts +3 -0
- package/dist/infrastructure/repository/context.js +20 -0
- package/dist/infrastructure/repository/refs.d.ts +3 -0
- package/dist/infrastructure/repository/refs.js +37 -0
- package/dist/{repo-registry.d.ts → infrastructure/repository/registry.d.ts} +1 -5
- package/dist/{repo-registry.js → infrastructure/repository/registry.js} +1 -1
- package/dist/infrastructure/repository/worktrees.d.ts +2 -0
- package/dist/infrastructure/repository/worktrees.js +48 -0
- package/dist/{uv-validation.d.ts → infrastructure/validation/uv.d.ts} +1 -1
- package/dist/{uv-validation.js → infrastructure/validation/uv.js} +1 -1
- package/dist/infrastructure/worktree/bootstrap.d.ts +3 -0
- package/dist/{worktree-bootstrap.js → infrastructure/worktree/bootstrap.js} +7 -10
- package/dist/infrastructure/worktree/info.d.ts +6 -0
- package/dist/infrastructure/worktree/info.js +61 -0
- package/dist/{worktree-management.d.ts → infrastructure/worktree/lifecycle.d.ts} +0 -6
- package/dist/{worktree-management.js → infrastructure/worktree/lifecycle.js} +1 -9
- package/dist/ports/bootstrap.d.ts +61 -0
- package/dist/ports/bootstrap.js +1 -0
- package/dist/ports/config.d.ts +21 -0
- package/dist/ports/config.js +17 -0
- package/dist/ports/editor.d.ts +6 -0
- package/dist/ports/editor.js +1 -0
- package/dist/ports/git.d.ts +8 -0
- package/dist/ports/git.js +1 -0
- package/dist/ports/history.d.ts +5 -0
- package/dist/ports/history.js +1 -0
- package/dist/ports/hooks.d.ts +12 -0
- package/dist/ports/hooks.js +1 -0
- package/dist/{command-runner.d.ts → ports/process.d.ts} +0 -1
- package/dist/ports/process.js +1 -0
- package/dist/ports/pull-requests.d.ts +11 -0
- package/dist/ports/pull-requests.js +1 -0
- package/dist/ports/repository.d.ts +17 -0
- package/dist/ports/repository.js +1 -0
- package/dist/{bootstrap-output.d.ts → presentation/bootstrap/output.d.ts} +1 -1
- package/dist/presentation/bootstrap/preview.d.ts +2 -0
- package/dist/{bootstrap-preview.js → presentation/bootstrap/preview.js} +0 -4
- package/dist/{shell-completion.js → presentation/shell/completion.js} +5 -4
- package/dist/presentation/terminal/context-card.d.ts +2 -0
- package/dist/{context-card.js → presentation/terminal/context-card.js} +3 -12
- package/dist/presentation/worktree/format.d.ts +4 -0
- package/dist/presentation/worktree/format.js +41 -0
- package/dist/{worktree-picker.d.ts → presentation/worktree/picker.d.ts} +7 -11
- package/dist/{worktree-picker.js → presentation/worktree/picker.js} +11 -182
- package/man/man1/gji-back.1 +1 -1
- package/man/man1/gji-clean.1 +1 -1
- package/man/man1/gji-completion.1 +1 -1
- package/man/man1/gji-config.1 +1 -1
- package/man/man1/gji-doctor.1 +1 -1
- package/man/man1/gji-done.1 +1 -1
- package/man/man1/gji-go.1 +1 -1
- package/man/man1/gji-history.1 +1 -1
- package/man/man1/gji-init.1 +1 -1
- package/man/man1/gji-ls.1 +1 -1
- package/man/man1/gji-new.1 +6 -3
- package/man/man1/gji-open.1 +1 -1
- package/man/man1/gji-pr.1 +1 -1
- package/man/man1/gji-remove.1 +1 -1
- package/man/man1/gji-root.1 +1 -1
- package/man/man1/gji-run-hook.1 +1 -1
- package/man/man1/gji-status.1 +1 -1
- package/man/man1/gji-sync-files.1 +1 -1
- package/man/man1/gji-sync.1 +1 -1
- package/man/man1/gji-task.1 +1 -1
- package/man/man1/gji-undo.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +2 -2
- package/package.json +1 -1
- package/dist/bootstrap-preview.d.ts +0 -9
- package/dist/context-card.d.ts +0 -1
- package/dist/format-bytes.d.ts +0 -1
- package/dist/format-bytes.js +0 -14
- package/dist/git.d.ts +0 -18
- package/dist/repo.d.ts +0 -20
- package/dist/repo.js +0 -161
- package/dist/worktree-bootstrap.d.ts +0 -24
- package/dist/worktree-info.d.ts +0 -37
- package/dist/worktree-info.js +0 -123
- package/dist/worktree-sources.d.ts +0 -4
- /package/dist/{worktree-source.js → application/worktree/read-models.js} +0 -0
- /package/dist/{completion.d.ts → cli/commands/completion.d.ts} +0 -0
- /package/dist/{headless.d.ts → cli/runtime/headless.d.ts} +0 -0
- /package/dist/{headless.js → cli/runtime/headless.js} +0 -0
- /package/dist/{paths.d.ts → domain/shared/paths.d.ts} +0 -0
- /package/dist/{paths.js → domain/shared/paths.js} +0 -0
- /package/dist/{file-sync.d.ts → infrastructure/filesystem/file-sync.d.ts} +0 -0
- /package/dist/{file-sync.js → infrastructure/filesystem/file-sync.js} +0 -0
- /package/dist/{fs-utils.d.ts → infrastructure/filesystem/fs-utils.d.ts} +0 -0
- /package/dist/{fs-utils.js → infrastructure/filesystem/fs-utils.js} +0 -0
- /package/dist/{safe-destination.d.ts → infrastructure/filesystem/safe-destination.d.ts} +0 -0
- /package/dist/{safe-destination.js → infrastructure/filesystem/safe-destination.js} +0 -0
- /package/dist/{browser.d.ts → infrastructure/integrations/browser.d.ts} +0 -0
- /package/dist/{browser.js → infrastructure/integrations/browser.js} +0 -0
- /package/dist/{editor.js → infrastructure/integrations/editor.js} +0 -0
- /package/dist/{pull-requests.js → infrastructure/integrations/pull-requests.js} +0 -0
- /package/dist/{history.js → infrastructure/persistence/history.js} +0 -0
- /package/dist/{slots.d.ts → infrastructure/persistence/slots.d.ts} +0 -0
- /package/dist/{slots.js → infrastructure/persistence/slots.js} +0 -0
- /package/dist/{task.d.ts → infrastructure/persistence/task.d.ts} +0 -0
- /package/dist/{command-runner.js → infrastructure/process/command-runner.js} +0 -0
- /package/dist/{hooks.js → infrastructure/process/hooks.js} +0 -0
- /package/dist/{bootstrap-output.js → presentation/bootstrap/output.js} +0 -0
- /package/dist/{conflict.d.ts → presentation/prompts/path-conflict.d.ts} +0 -0
- /package/dist/{conflict.js → presentation/prompts/path-conflict.js} +0 -0
- /package/dist/{shell-completion.d.ts → presentation/shell/completion.d.ts} +0 -0
- /package/dist/{shell-handoff.d.ts → presentation/shell/handoff.d.ts} +0 -0
- /package/dist/{shell-handoff.js → presentation/shell/handoff.js} +0 -0
- /package/dist/{shell-setup.d.ts → presentation/shell/setup.d.ts} +0 -0
- /package/dist/{shell-setup.js → presentation/shell/setup.js} +0 -0
- /package/dist/{shell.d.ts → presentation/shell/shell.d.ts} +0 -0
- /package/dist/{shell.js → presentation/shell/shell.js} +0 -0
- /package/dist/{navigation-output.d.ts → presentation/terminal/navigation.d.ts} +0 -0
- /package/dist/{navigation-output.js → presentation/terminal/navigation.js} +0 -0
- /package/dist/{terminal-text.d.ts → presentation/terminal/text.d.ts} +0 -0
- /package/dist/{terminal-text.js → presentation/terminal/text.js} +0 -0
- /package/dist/{worktree-prompts.d.ts → presentation/worktree/prompts.d.ts} +0 -0
- /package/dist/{worktree-prompts.js → presentation/worktree/prompts.js} +0 -0
package/README.md
CHANGED
|
@@ -22,6 +22,18 @@ directory. For repeatable workflows, you can still provide a branch directly:
|
|
|
22
22
|
gji new feature/payment-refactor
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
If you prefer to reuse the current worktree, create a branch in place and
|
|
26
|
+
refresh the configured default branch first:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
gji new --branch-only feature/payment-refactor
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This creates the new branch from the latest configured remote default branch
|
|
33
|
+
without creating another worktree or installing dependencies. The current
|
|
34
|
+
worktree must be clean; use `--no-fetch` to create from the local default
|
|
35
|
+
branch as-is.
|
|
36
|
+
|
|
25
37
|
## The problem
|
|
26
38
|
|
|
27
39
|
You are halfway through a feature when someone asks you to review a pull
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RepositoryContext } from "../../domain/repository/context.js";
|
|
2
|
+
import type { WorktreeSource } from "../../domain/worktree/source.js";
|
|
3
|
+
import type { WorktreeEntry } from "../../domain/worktree/types.js";
|
|
4
|
+
import type { PullRequestInfo, PullRequestPort } from "../../ports/pull-requests.js";
|
|
5
|
+
import type { RepositoryContextPort, WorktreePort } from "../../ports/repository.js";
|
|
6
|
+
import type { WorktreeInfo } from "./read-models.js";
|
|
7
|
+
export interface LinkedWorktreeContext {
|
|
8
|
+
linkedWorktrees: WorktreeEntry[];
|
|
9
|
+
repository: RepositoryContext;
|
|
10
|
+
}
|
|
11
|
+
export type WorktreeMetadataMode = "full" | "fast";
|
|
12
|
+
export interface HydratedWorktree {
|
|
13
|
+
info: WorktreeInfo;
|
|
14
|
+
lastUsedTimestamp: number | null;
|
|
15
|
+
pullRequests: PullRequestInfo[];
|
|
16
|
+
source: WorktreeSource;
|
|
17
|
+
}
|
|
18
|
+
export interface WorktreeCatalogDependencies {
|
|
19
|
+
loadHistory: () => Promise<ReadonlyArray<{
|
|
20
|
+
path: string;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
}>>;
|
|
23
|
+
readTask: (worktreePath: string) => Promise<{
|
|
24
|
+
task: string;
|
|
25
|
+
} | null>;
|
|
26
|
+
readWorktreeInfos: (worktrees: WorktreeEntry[]) => Promise<WorktreeInfo[]>;
|
|
27
|
+
queryPullRequests?: PullRequestPort["listOpenPullRequests"];
|
|
28
|
+
queryRepositoryPullRequests?: PullRequestPort["listOpenPullRequestsForRepository"];
|
|
29
|
+
}
|
|
30
|
+
export declare function loadWorktreeCatalog(sources: WorktreeSource[], metadata: WorktreeMetadataMode, dependencies: WorktreeCatalogDependencies): Promise<HydratedWorktree[]>;
|
|
31
|
+
export declare function loadLinkedWorktrees(cwd: string, repositoryPort: RepositoryContextPort & WorktreePort): Promise<LinkedWorktreeContext>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { mapWithConcurrency } from "../../domain/shared/concurrency.js";
|
|
2
|
+
const MAX_PULL_REQUEST_REPOSITORY_QUERY_CONCURRENCY = 4;
|
|
3
|
+
const MAX_TASK_READ_CONCURRENCY = 8;
|
|
4
|
+
export async function loadWorktreeCatalog(sources, metadata, dependencies) {
|
|
5
|
+
const includeMetadata = metadata === "full";
|
|
6
|
+
const repositoryPullRequests = includeMetadata && dependencies.queryRepositoryPullRequests !== undefined
|
|
7
|
+
? readRepositoryPullRequests(sources, dependencies.queryRepositoryPullRequests)
|
|
8
|
+
: Promise.resolve(null);
|
|
9
|
+
const [history, infos, pullRequestsByRepository] = await Promise.all([
|
|
10
|
+
dependencies.loadHistory(),
|
|
11
|
+
includeMetadata
|
|
12
|
+
? dependencies.readWorktreeInfos(sources.map((source) => source.worktree))
|
|
13
|
+
: mapWithConcurrency(sources, MAX_TASK_READ_CONCURRENCY, async (source) => createUnhydratedWorktreeInfo(source.worktree, dependencies.readTask)),
|
|
14
|
+
repositoryPullRequests,
|
|
15
|
+
]);
|
|
16
|
+
const pullRequests = includeMetadata
|
|
17
|
+
? await Promise.all(sources.map((source) => readSourcePullRequests(source, dependencies.queryPullRequests, pullRequestsByRepository)))
|
|
18
|
+
: sources.map(() => []);
|
|
19
|
+
const historyByPath = new Map(history.map((entry) => [entry.path, entry]));
|
|
20
|
+
return sources.map((source, index) => ({
|
|
21
|
+
info: infos[index],
|
|
22
|
+
lastUsedTimestamp: historyByPath.get(source.worktree.path)?.timestamp ?? null,
|
|
23
|
+
pullRequests: pullRequests[index],
|
|
24
|
+
source,
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
export async function loadLinkedWorktrees(cwd, repositoryPort) {
|
|
28
|
+
const repository = await repositoryPort.detectRepository(cwd);
|
|
29
|
+
const linkedWorktrees = (await repositoryPort.listWorktrees(cwd)).filter((worktree) => worktree.path !== repository.repoRoot);
|
|
30
|
+
return {
|
|
31
|
+
linkedWorktrees,
|
|
32
|
+
repository,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function createUnhydratedWorktreeInfo(worktree, readTask) {
|
|
36
|
+
let task = null;
|
|
37
|
+
try {
|
|
38
|
+
task = (await readTask(worktree.path))?.task ?? null;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Task metadata is optional picker decoration.
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
...worktree,
|
|
45
|
+
lastCommitTimestamp: null,
|
|
46
|
+
slot: null,
|
|
47
|
+
status: "unknown",
|
|
48
|
+
task,
|
|
49
|
+
upstream: { kind: "unknown" },
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function readSourcePullRequests(source, queryPullRequests, pullRequestsByRepository) {
|
|
53
|
+
if (source.repoRoot === undefined || source.worktree.branch === null) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
if (pullRequestsByRepository !== null) {
|
|
57
|
+
return sortPullRequests(pullRequestsByRepository
|
|
58
|
+
.get(source.repoRoot)
|
|
59
|
+
?.filter((pullRequest) => pullRequest.sourceBranch === source.worktree.branch));
|
|
60
|
+
}
|
|
61
|
+
if (queryPullRequests === undefined)
|
|
62
|
+
return [];
|
|
63
|
+
try {
|
|
64
|
+
return sortPullRequests(await queryPullRequests(source.repoRoot, source.worktree.branch));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function readRepositoryPullRequests(sources, queryPullRequests) {
|
|
71
|
+
const repoRoots = [
|
|
72
|
+
...new Set(sources.flatMap((source) => source.repoRoot === undefined || source.worktree.branch === null
|
|
73
|
+
? []
|
|
74
|
+
: [source.repoRoot])),
|
|
75
|
+
];
|
|
76
|
+
const results = await mapWithConcurrency(repoRoots, MAX_PULL_REQUEST_REPOSITORY_QUERY_CONCURRENCY, async (repoRoot) => {
|
|
77
|
+
try {
|
|
78
|
+
return [repoRoot, sortPullRequests(await queryPullRequests(repoRoot))];
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [repoRoot, []];
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return new Map(results);
|
|
85
|
+
}
|
|
86
|
+
function sortPullRequests(pullRequests) {
|
|
87
|
+
return [...(pullRequests ?? [])].sort((left, right) => left.number - right.number);
|
|
88
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorktreeEntry } from "../../domain/worktree/types.js";
|
|
2
|
+
import type { WorktreeInfo } from "./read-models.js";
|
|
3
|
+
export interface ContextCardDependencies {
|
|
4
|
+
listWorktrees: (cwd: string) => Promise<WorktreeEntry[]>;
|
|
5
|
+
readTask: (worktreePath: string) => Promise<{
|
|
6
|
+
task: string;
|
|
7
|
+
} | null>;
|
|
8
|
+
readWorktreeInfo: (worktree: WorktreeEntry) => Promise<WorktreeInfo>;
|
|
9
|
+
}
|
|
10
|
+
export interface ContextCardModel {
|
|
11
|
+
info: WorktreeInfo;
|
|
12
|
+
task: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function loadContextCardModel(worktreePath: string, dependencies: ContextCardDependencies): Promise<ContextCardModel | null>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export async function loadContextCardModel(worktreePath, dependencies) {
|
|
2
|
+
const worktree = (await dependencies.listWorktrees(worktreePath)).find((entry) => entry.path === worktreePath);
|
|
3
|
+
if (!worktree)
|
|
4
|
+
return null;
|
|
5
|
+
const task = await dependencies.readTask(worktreePath);
|
|
6
|
+
if (!task)
|
|
7
|
+
return null;
|
|
8
|
+
return {
|
|
9
|
+
info: await dependencies.readWorktreeInfo(worktree),
|
|
10
|
+
task: task.task,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { WorktreeSource } from "
|
|
3
|
-
|
|
1
|
+
import type { RepositoryContext } from "../../domain/repository/context.js";
|
|
2
|
+
import type { WorktreeSource } from "../../domain/worktree/source.js";
|
|
3
|
+
import type { ConfigPort } from "../../ports/config.js";
|
|
4
|
+
import type { RepositoryContextPort, RepositoryRefPort, RepositoryRegistryPort, WorktreePort } from "../../ports/repository.js";
|
|
5
|
+
type GoBranchResolutionBase = {
|
|
4
6
|
kind: "existing";
|
|
5
7
|
source: WorktreeSource;
|
|
6
8
|
} | {
|
|
@@ -26,10 +28,16 @@ export type GoBranchResolution = {
|
|
|
26
28
|
kind: "error";
|
|
27
29
|
message: string;
|
|
28
30
|
};
|
|
31
|
+
export type GoBranchResolution = GoBranchResolutionBase & {
|
|
32
|
+
configWarnings?: readonly string[];
|
|
33
|
+
};
|
|
29
34
|
export declare function resolveGoBranch(options: {
|
|
30
35
|
branch: string;
|
|
31
|
-
configStderr?: (chunk: string) => void;
|
|
32
36
|
cwd: string;
|
|
33
37
|
currentSources: WorktreeSource[];
|
|
34
38
|
repository: RepositoryContext | null;
|
|
39
|
+
repositoryPort: RepositoryRefPort;
|
|
40
|
+
sourceDependencies: RepositoryContextPort & RepositoryRegistryPort & WorktreePort;
|
|
41
|
+
configPort: ConfigPort;
|
|
35
42
|
}): Promise<GoBranchResolution>;
|
|
43
|
+
export {};
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parsePrInput } from "
|
|
3
|
-
import {
|
|
4
|
-
import { resolveExactWorktreeQueryMatches, resolveWorktreeQuery, resolveWorktreeQueryMatches, } from "./worktree-picker.js";
|
|
5
|
-
import { listRegisteredWorktreeSources } from "./worktree-sources.js";
|
|
1
|
+
import { resolveExactWorktreeQueryMatches, resolveWorktreeQuery, resolveWorktreeQueryMatches, } from "../../domain/worktree/matching.js";
|
|
2
|
+
import { parsePrInput } from "../../domain/worktree/pr-reference.js";
|
|
3
|
+
import { listRegisteredWorktreeSources } from "./sources.js";
|
|
6
4
|
export async function resolveGoBranch(options) {
|
|
7
|
-
const { branch,
|
|
5
|
+
const { branch, configPort, cwd, currentSources, repository, repositoryPort, sourceDependencies, } = options;
|
|
8
6
|
const pullRequestNumber = parsePrInput(branch);
|
|
9
7
|
const exactCurrentMatches = resolveExistingExactWorktreeMatches(currentSources, branch, false);
|
|
10
8
|
if (exactCurrentMatches.length === 1) {
|
|
11
9
|
return { kind: "existing", source: exactCurrentMatches[0] };
|
|
12
10
|
}
|
|
13
11
|
const localBranch = repository
|
|
14
|
-
? await hasLocalBranch(repository.repoRoot, branch)
|
|
12
|
+
? await repositoryPort.hasLocalBranch(repository.repoRoot, branch)
|
|
15
13
|
: false;
|
|
16
14
|
if (!repository && pullRequestNumber !== null) {
|
|
17
15
|
return {
|
|
@@ -25,11 +23,9 @@ export async function resolveGoBranch(options) {
|
|
|
25
23
|
const configWarnings = [];
|
|
26
24
|
if (repository) {
|
|
27
25
|
try {
|
|
28
|
-
const config = await loadEffectiveConfig(repository.repoRoot, undefined,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
remote = resolveConfigString(config, "syncRemote") ?? "origin";
|
|
32
|
-
remoteBranch = await hasRemoteBranch(repository.repoRoot, remote, branch);
|
|
26
|
+
const config = await configPort.loadEffectiveConfig(repository.repoRoot, undefined, (warning) => configWarnings.push(warning));
|
|
27
|
+
remote = configPort.resolveConfigString(config, "syncRemote") ?? "origin";
|
|
28
|
+
remoteBranch = await repositoryPort.hasRemoteBranch(repository.repoRoot, remote, branch);
|
|
33
29
|
}
|
|
34
30
|
catch (error) {
|
|
35
31
|
configError = {
|
|
@@ -38,14 +34,8 @@ export async function resolveGoBranch(options) {
|
|
|
38
34
|
};
|
|
39
35
|
}
|
|
40
36
|
}
|
|
41
|
-
const flushConfigWarnings = () => {
|
|
42
|
-
if (configStderr === undefined)
|
|
43
|
-
return;
|
|
44
|
-
for (const warning of configWarnings)
|
|
45
|
-
configStderr(warning);
|
|
46
|
-
};
|
|
47
37
|
const pullRequestBelongsToRepository = repository && pullRequestNumber !== null
|
|
48
|
-
? await isPullRequestForRepository(repository.repoRoot, branch)
|
|
38
|
+
? await isPullRequestForRepository(repository.repoRoot, branch, repositoryPort)
|
|
49
39
|
: true;
|
|
50
40
|
if (pullRequestNumber !== null &&
|
|
51
41
|
!localBranch &&
|
|
@@ -53,60 +43,72 @@ export async function resolveGoBranch(options) {
|
|
|
53
43
|
pullRequestBelongsToRepository) {
|
|
54
44
|
const pullRequestMatches = resolveExistingExactWorktreeMatches(currentSources, branch, true);
|
|
55
45
|
if (pullRequestMatches.length === 1) {
|
|
56
|
-
return { kind: "existing", source: pullRequestMatches[0] };
|
|
46
|
+
return finish({ kind: "existing", source: pullRequestMatches[0] }, false);
|
|
57
47
|
}
|
|
58
48
|
}
|
|
59
49
|
let skippedRegisteredRepos = 0;
|
|
60
|
-
const registeredSources = await listRegisteredWorktreeSources(cwd, () => {
|
|
50
|
+
const registeredSources = await listRegisteredWorktreeSources(cwd, sourceDependencies, () => {
|
|
61
51
|
skippedRegisteredRepos++;
|
|
62
52
|
});
|
|
63
53
|
const crossRepoSources = registeredSources.filter((source) => source.repoRoot !== repository?.repoRoot);
|
|
64
|
-
const crossMatches = await resolveExistingWorktreeMatches(crossRepoSources, branch, (!localBranch && !remoteBranch) || isPullRequestUrl(branch));
|
|
54
|
+
const crossMatches = await resolveExistingWorktreeMatches(crossRepoSources, branch, (!localBranch && !remoteBranch) || isPullRequestUrl(branch), repositoryPort);
|
|
65
55
|
if (crossMatches.length === 1) {
|
|
66
|
-
return { kind: "existing", source: crossMatches[0] };
|
|
56
|
+
return finish({ kind: "existing", source: crossMatches[0] }, false);
|
|
67
57
|
}
|
|
68
58
|
if (crossMatches.length > 1) {
|
|
69
|
-
return { kind: "ambiguous", matches: crossMatches };
|
|
59
|
+
return finish({ kind: "ambiguous", matches: crossMatches }, false);
|
|
70
60
|
}
|
|
71
61
|
if (!repository) {
|
|
72
|
-
return registeredSources.length === 0
|
|
62
|
+
return finish(registeredSources.length === 0
|
|
73
63
|
? {
|
|
74
64
|
kind: "no-repository",
|
|
75
65
|
staleRegisteredRepos: skippedRegisteredRepos > 0,
|
|
76
66
|
}
|
|
77
|
-
: {
|
|
67
|
+
: {
|
|
68
|
+
kind: "no-match",
|
|
69
|
+
staleRegisteredRepos: skippedRegisteredRepos > 0,
|
|
70
|
+
});
|
|
78
71
|
}
|
|
79
72
|
if (localBranch) {
|
|
80
73
|
if (configError)
|
|
81
|
-
return configError;
|
|
82
|
-
|
|
83
|
-
return { kind: "create", repository, branch, mode: "checkout" };
|
|
74
|
+
return finish(configError);
|
|
75
|
+
return finish({ kind: "create", repository, branch, mode: "checkout" });
|
|
84
76
|
}
|
|
85
77
|
if (remoteBranch) {
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
return finish({
|
|
79
|
+
kind: "create",
|
|
80
|
+
repository,
|
|
81
|
+
branch,
|
|
82
|
+
mode: "track",
|
|
83
|
+
remote,
|
|
84
|
+
});
|
|
88
85
|
}
|
|
89
86
|
const localMatch = !pullRequestNumber || !isPullRequestUrl(branch)
|
|
90
87
|
? resolveWorktreeQuery(currentSources, branch)
|
|
91
88
|
: null;
|
|
92
89
|
if (localMatch) {
|
|
93
|
-
return { kind: "existing", source: localMatch };
|
|
90
|
+
return finish({ kind: "existing", source: localMatch });
|
|
94
91
|
}
|
|
95
92
|
if (configError)
|
|
96
|
-
return configError;
|
|
93
|
+
return finish(configError);
|
|
97
94
|
if (pullRequestNumber !== null && !pullRequestBelongsToRepository) {
|
|
98
|
-
|
|
99
|
-
return {
|
|
95
|
+
return finish({
|
|
100
96
|
kind: "error",
|
|
101
97
|
message: "PR URL does not belong to this repository; run gji go from the matching checkout",
|
|
102
|
-
};
|
|
98
|
+
});
|
|
103
99
|
}
|
|
104
100
|
if (pullRequestNumber !== null) {
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
return finish({ kind: "pull-request", repository, input: branch });
|
|
102
|
+
}
|
|
103
|
+
return finish({
|
|
104
|
+
kind: "no-match",
|
|
105
|
+
staleRegisteredRepos: skippedRegisteredRepos > 0,
|
|
106
|
+
});
|
|
107
|
+
function finish(resolution, includeWarnings = true) {
|
|
108
|
+
return !includeWarnings || configWarnings.length === 0
|
|
109
|
+
? resolution
|
|
110
|
+
: { ...resolution, configWarnings };
|
|
107
111
|
}
|
|
108
|
-
flushConfigWarnings();
|
|
109
|
-
return { kind: "no-match", staleRegisteredRepos: skippedRegisteredRepos > 0 };
|
|
110
112
|
}
|
|
111
113
|
function resolveExistingExactWorktreeMatches(sources, query, allowPullRequestFallback) {
|
|
112
114
|
const exactMatches = resolveExactWorktreeQueryMatches(sources, query);
|
|
@@ -117,7 +119,7 @@ function resolveExistingExactWorktreeMatches(sources, query, allowPullRequestFal
|
|
|
117
119
|
? []
|
|
118
120
|
: resolveExactWorktreeQueryMatches(sources, `pr/${pullRequestNumber}`);
|
|
119
121
|
}
|
|
120
|
-
async function resolveExistingWorktreeMatches(sources, query, allowPullRequestFallback) {
|
|
122
|
+
async function resolveExistingWorktreeMatches(sources, query, allowPullRequestFallback, repositoryPort) {
|
|
121
123
|
const exactMatches = resolveExactWorktreeQueryMatches(sources, query);
|
|
122
124
|
if (exactMatches.length > 0)
|
|
123
125
|
return exactMatches;
|
|
@@ -132,7 +134,7 @@ async function resolveExistingWorktreeMatches(sources, query, allowPullRequestFa
|
|
|
132
134
|
const repoRoot = source.repoRoot ?? source.worktree.path;
|
|
133
135
|
let ownership = ownershipByRepository.get(repoRoot);
|
|
134
136
|
if (ownership === undefined) {
|
|
135
|
-
ownership = isPullRequestForRepository(repoRoot, query);
|
|
137
|
+
ownership = isPullRequestForRepository(repoRoot, query, repositoryPort);
|
|
136
138
|
ownershipByRepository.set(repoRoot, ownership);
|
|
137
139
|
}
|
|
138
140
|
return (await ownership) ? source : null;
|
|
@@ -146,7 +148,7 @@ async function resolveExistingWorktreeMatches(sources, query, allowPullRequestFa
|
|
|
146
148
|
function isPullRequestUrl(input) {
|
|
147
149
|
return /^[a-z][a-z\d+.-]*:\/\//i.test(input);
|
|
148
150
|
}
|
|
149
|
-
async function isPullRequestForRepository(repoRoot, input) {
|
|
151
|
+
async function isPullRequestForRepository(repoRoot, input, repositoryPort) {
|
|
150
152
|
if (/^\d+$/.test(input) || /^#\d+$/.test(input))
|
|
151
153
|
return true;
|
|
152
154
|
let pullRequestUrl;
|
|
@@ -156,7 +158,7 @@ async function isPullRequestForRepository(repoRoot, input) {
|
|
|
156
158
|
catch {
|
|
157
159
|
return true;
|
|
158
160
|
}
|
|
159
|
-
const remoteUrl = await getRepositoryRemoteUrl(repoRoot, "origin");
|
|
161
|
+
const remoteUrl = await repositoryPort.getRepositoryRemoteUrl(repoRoot, "origin");
|
|
160
162
|
if (!remoteUrl)
|
|
161
163
|
return true;
|
|
162
164
|
return (normalizeRepositoryUrl(remoteUrl) ===
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { WorktreeEntry } from "../../domain/worktree/types.js";
|
|
2
|
+
export type WorktreeStatus = "clean" | "dirty" | "unknown";
|
|
3
|
+
export type UpstreamState = {
|
|
4
|
+
kind: "detached";
|
|
5
|
+
} | {
|
|
6
|
+
kind: "no-upstream";
|
|
7
|
+
} | {
|
|
8
|
+
kind: "stale";
|
|
9
|
+
} | {
|
|
10
|
+
kind: "tracked";
|
|
11
|
+
ahead: number;
|
|
12
|
+
behind: number;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "unknown";
|
|
15
|
+
};
|
|
16
|
+
export interface WorktreeInfo extends WorktreeEntry {
|
|
17
|
+
lastCommitTimestamp: number | null;
|
|
18
|
+
slot: number | null;
|
|
19
|
+
status: WorktreeStatus;
|
|
20
|
+
task: string | null;
|
|
21
|
+
upstream: UpstreamState;
|
|
22
|
+
}
|
|
23
|
+
export interface SerializedWorktreeInfo {
|
|
24
|
+
branch: string | null;
|
|
25
|
+
lastCommitTimestamp: number | null;
|
|
26
|
+
path: string;
|
|
27
|
+
slot: number | null;
|
|
28
|
+
status: WorktreeStatus;
|
|
29
|
+
task: string | null;
|
|
30
|
+
upstream: UpstreamState;
|
|
31
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RepoRegistryEntry } from "../../domain/repository/registry.js";
|
|
2
|
+
import type { WorktreeSource } from "../../domain/worktree/source.js";
|
|
3
|
+
import type { RepositoryContextPort, RepositoryRegistryPort, WorktreePort } from "../../ports/repository.js";
|
|
4
|
+
type WorktreeSourceDependencies = RepositoryContextPort & RepositoryRegistryPort & WorktreePort;
|
|
5
|
+
export declare function listRegisteredWorktreeSources(cwd: string, repositoryPort: WorktreeSourceDependencies, onSkipped?: (entry: RepoRegistryEntry) => void): Promise<WorktreeSource[]>;
|
|
6
|
+
export declare function listDiscoverableWorktreeSources(cwd: string, repositoryPort: WorktreeSourceDependencies, onSkipped?: (entry: RepoRegistryEntry) => void): Promise<WorktreeSource[]>;
|
|
7
|
+
export {};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { loadRegistry } from "./repo-registry.js";
|
|
1
|
+
import { mapWithConcurrency } from "../../domain/shared/concurrency.js";
|
|
3
2
|
const MAX_REPOSITORY_DISCOVERY_CONCURRENCY = 4;
|
|
4
|
-
export async function listRegisteredWorktreeSources(cwd, onSkipped) {
|
|
5
|
-
const registry = await loadRegistry();
|
|
6
|
-
const currentRoot = await
|
|
3
|
+
export async function listRegisteredWorktreeSources(cwd, repositoryPort, onSkipped) {
|
|
4
|
+
const registry = await repositoryPort.loadRegistry();
|
|
5
|
+
const currentRoot = await repositoryPort
|
|
6
|
+
.detectRepository(cwd)
|
|
7
7
|
.then((repository) => repository.currentRoot)
|
|
8
8
|
.catch(() => null);
|
|
9
9
|
const results = await mapWithConcurrency(registry, MAX_REPOSITORY_DISCOVERY_CONCURRENCY, async (entry) => {
|
|
10
10
|
try {
|
|
11
|
-
const worktrees = await listWorktrees(entry.path);
|
|
11
|
+
const worktrees = await repositoryPort.listWorktrees(entry.path);
|
|
12
12
|
return { entry, worktrees };
|
|
13
13
|
}
|
|
14
14
|
catch {
|
|
@@ -34,14 +34,16 @@ export async function listRegisteredWorktreeSources(cwd, onSkipped) {
|
|
|
34
34
|
}
|
|
35
35
|
return allItems;
|
|
36
36
|
}
|
|
37
|
-
export async function listDiscoverableWorktreeSources(cwd, onSkipped) {
|
|
38
|
-
const currentRepository = await
|
|
39
|
-
|
|
37
|
+
export async function listDiscoverableWorktreeSources(cwd, repositoryPort, onSkipped) {
|
|
38
|
+
const currentRepository = await repositoryPort
|
|
39
|
+
.detectRepository(cwd)
|
|
40
|
+
.catch(() => null);
|
|
41
|
+
const registeredSources = await listRegisteredWorktreeSources(cwd, repositoryPort, onSkipped);
|
|
40
42
|
if (currentRepository === null)
|
|
41
43
|
return dedupeSources(registeredSources);
|
|
42
44
|
let currentSources = [];
|
|
43
45
|
try {
|
|
44
|
-
currentSources = (await listWorktrees(cwd)).map((worktree) => ({
|
|
46
|
+
currentSources = (await repositoryPort.listWorktrees(cwd)).map((worktree) => ({
|
|
45
47
|
repoName: currentRepository.repoName,
|
|
46
48
|
repoRoot: currentRepository.repoRoot,
|
|
47
49
|
worktree,
|
|
@@ -52,20 +54,6 @@ export async function listDiscoverableWorktreeSources(cwd, onSkipped) {
|
|
|
52
54
|
}
|
|
53
55
|
return dedupeSources([...currentSources, ...registeredSources]);
|
|
54
56
|
}
|
|
55
|
-
async function mapWithConcurrency(items, limit, mapper) {
|
|
56
|
-
const results = new Array(items.length);
|
|
57
|
-
let nextIndex = 0;
|
|
58
|
-
async function readNext() {
|
|
59
|
-
for (;;) {
|
|
60
|
-
const index = nextIndex++;
|
|
61
|
-
if (index >= items.length)
|
|
62
|
-
return;
|
|
63
|
-
results[index] = await mapper(items[index]);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => readNext()));
|
|
67
|
-
return results;
|
|
68
|
-
}
|
|
69
57
|
function dedupeSources(sources) {
|
|
70
58
|
const seen = new Set();
|
|
71
59
|
return sources.filter((source) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { HistoryEntry } from "../../ports/history.js";
|
|
2
|
+
import { type CliRuntime } from "../dependencies.js";
|
|
2
3
|
export declare const BACK_OUTPUT_FILE_ENV = "GJI_BACK_OUTPUT_FILE";
|
|
3
4
|
export interface BackCommandOptions {
|
|
4
5
|
cwd: string;
|
|
@@ -8,6 +9,7 @@ export interface BackCommandOptions {
|
|
|
8
9
|
commandName?: string;
|
|
9
10
|
outputEnv?: string;
|
|
10
11
|
print?: boolean;
|
|
12
|
+
runtime?: CliRuntime<"config" | "historyStore" | "hooks" | "repositoryContext">;
|
|
11
13
|
stderr: (chunk: string) => void;
|
|
12
14
|
stdout: (chunk: string) => void;
|
|
13
15
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { access } from "node:fs/promises";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { createNavigationRepository, createNavigationTarget, } from "./navigation-output.js";
|
|
7
|
-
import { detectRepository } from "./repo.js";
|
|
8
|
-
import { writeShellOutput } from "./shell-handoff.js";
|
|
3
|
+
import { writeShellOutput } from "../../presentation/shell/handoff.js";
|
|
4
|
+
import { createNavigationRepository, createNavigationTarget, } from "../../presentation/terminal/navigation.js";
|
|
5
|
+
import { defaultCliDependencies } from "../dependencies.js";
|
|
9
6
|
export const BACK_OUTPUT_FILE_ENV = "GJI_BACK_OUTPUT_FILE";
|
|
10
7
|
export async function runBackCommand(options) {
|
|
8
|
+
const runtime = options.runtime ?? defaultCliDependencies;
|
|
9
|
+
const { loadEffectiveConfig } = runtime.config;
|
|
10
|
+
const { appendHistory, loadHistory } = runtime.historyStore;
|
|
11
|
+
const { extractHooks, runHook } = runtime.hooks;
|
|
12
|
+
const { detectRepository } = runtime.repositoryContext;
|
|
11
13
|
const history = await loadHistory(options.home);
|
|
12
14
|
const steps = options.n ?? 1;
|
|
13
15
|
if (steps < 1) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { WorktreeEntry } from "
|
|
2
|
-
import { type WorktreePromptEntry } from "
|
|
1
|
+
import type { WorktreeEntry } from "../../domain/worktree/types.js";
|
|
2
|
+
import { type WorktreePromptEntry } from "../../presentation/worktree/picker.js";
|
|
3
|
+
import { type CliRuntime } from "../dependencies.js";
|
|
3
4
|
export interface CleanCommandOptions {
|
|
4
5
|
cwd: string;
|
|
5
6
|
dryRun?: boolean;
|
|
6
7
|
force?: boolean;
|
|
7
8
|
json?: boolean;
|
|
8
9
|
stale?: boolean;
|
|
10
|
+
runtime?: CliRuntime<"git" | "config" | "configStore" | "slots" | "repositoryContext" | "repositoryRegistry" | "worktrees" | "worktreeInfo" | "worktreeLifecycle" | "worktreeCatalog">;
|
|
9
11
|
stderr: (chunk: string) => void;
|
|
10
12
|
stdout: (chunk: string) => void;
|
|
11
13
|
}
|