@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.
- 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 +7100 -6265
- 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} +36 -191
- 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
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { type CliRuntime } from "../dependencies.js";
|
|
1
2
|
export interface SyncCommandOptions {
|
|
2
3
|
all?: boolean;
|
|
3
4
|
cwd: string;
|
|
4
5
|
json?: boolean;
|
|
6
|
+
runtime?: CliRuntime<"git" | "config" | "repositoryContext" | "worktrees">;
|
|
5
7
|
stderr: (chunk: string) => void;
|
|
6
8
|
stdout: (chunk: string) => void;
|
|
7
9
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { comparePaths } from "./paths.js";
|
|
4
|
-
import { detectRepository, listWorktrees } from "./repo.js";
|
|
1
|
+
import { comparePaths } from "../../domain/shared/paths.js";
|
|
2
|
+
import { defaultCliDependencies } from "../dependencies.js";
|
|
5
3
|
export async function runSyncCommand(options) {
|
|
4
|
+
const runtime = options.runtime ?? defaultCliDependencies;
|
|
5
|
+
const { isDirtyWorktree, resolveRemoteBase, runGit } = runtime.git;
|
|
6
|
+
const { loadEffectiveConfig } = runtime.config;
|
|
7
|
+
const { detectRepository } = runtime.repositoryContext;
|
|
8
|
+
const { listWorktrees } = runtime.worktrees;
|
|
6
9
|
const repository = await detectRepository(options.cwd);
|
|
7
10
|
const config = await loadEffectiveConfig(repository.repoRoot, undefined, options.stderr);
|
|
8
11
|
const worktrees = await listWorktrees(options.cwd);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type CliRuntime } from "../dependencies.js";
|
|
1
2
|
export interface TaskCommandOptions {
|
|
2
3
|
clear?: boolean;
|
|
3
4
|
cwd: string;
|
|
4
5
|
json?: boolean;
|
|
5
6
|
task?: string;
|
|
7
|
+
runtime?: CliRuntime<"tasks" | "repositoryContext">;
|
|
6
8
|
stderr: (chunk: string) => void;
|
|
7
9
|
stdout: (chunk: string) => void;
|
|
8
10
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { clearTask, readTask, writeTask } from "./task.js";
|
|
1
|
+
import { defaultCliDependencies } from "../dependencies.js";
|
|
3
2
|
export async function runTaskCommand(options) {
|
|
3
|
+
const runtime = options.runtime ?? defaultCliDependencies;
|
|
4
|
+
const { clearTask, readTask, writeTask } = runtime.tasks;
|
|
5
|
+
const { detectRepository } = runtime.repositoryContext;
|
|
4
6
|
const repository = await detectRepository(options.cwd);
|
|
5
7
|
if (options.clear && options.task !== undefined)
|
|
6
8
|
return emitTaskError(options, "--clear cannot be combined with a task");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { WorktreeEntry } from "../../domain/worktree/types.js";
|
|
2
|
+
import { type CliRuntime } from "../dependencies.js";
|
|
2
3
|
export type UndoOperation = "remove" | "clean" | "done";
|
|
3
4
|
export interface UndoEntry {
|
|
4
5
|
branch: string | null;
|
|
@@ -25,12 +26,13 @@ export interface UndoCommandOptions {
|
|
|
25
26
|
id?: string;
|
|
26
27
|
list?: boolean;
|
|
27
28
|
json?: boolean;
|
|
29
|
+
runtime?: CliRuntime<"git" | "configStore" | "repositoryContext">;
|
|
28
30
|
stderr: (chunk: string) => void;
|
|
29
31
|
stdout: (chunk: string) => void;
|
|
30
32
|
}
|
|
31
|
-
export declare function undoLogPath(home?: string): string;
|
|
32
|
-
export declare function loadUndoRecords(home?: string): Promise<UndoRecord[]>;
|
|
33
|
-
export declare function recordUndoOperation(op: UndoOperation, repoRoot: string, worktrees: WorktreeEntry[], home?: string): Promise<UndoRecord | null>;
|
|
34
|
-
export declare function finalizeUndoOperation(record: UndoRecord, removedWorktrees: WorktreeEntry[], home?: string): Promise<void>;
|
|
35
|
-
export declare function restoreUndoRecord(record: UndoRecord, home?: string): Promise<UndoRestoreResult>;
|
|
33
|
+
export declare function undoLogPath(home?: string, globalConfigDirectory?: ".config/gji"): string;
|
|
34
|
+
export declare function loadUndoRecords(home?: string, globalConfigDirectory?: ".config/gji"): Promise<UndoRecord[]>;
|
|
35
|
+
export declare function recordUndoOperation(op: UndoOperation, repoRoot: string, worktrees: WorktreeEntry[], home?: string, runtime?: CliRuntime<"git" | "configStore">): Promise<UndoRecord | null>;
|
|
36
|
+
export declare function finalizeUndoOperation(record: UndoRecord, removedWorktrees: WorktreeEntry[], home?: string, globalConfigDirectory?: ".config/gji"): Promise<void>;
|
|
37
|
+
export declare function restoreUndoRecord(record: UndoRecord, home?: string, runtime?: CliRuntime<"git" | "configStore">): Promise<UndoRestoreResult>;
|
|
36
38
|
export declare function runUndoCommand(options: UndoCommandOptions): Promise<number>;
|
|
@@ -2,29 +2,31 @@ import { access, mkdir, open, readFile, rename, stat, unlink, writeFile, } from
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { confirm, isCancel } from "@clack/prompts";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { isHeadless } from "./headless.js";
|
|
8
|
-
import { detectRepository } from "./repo.js";
|
|
5
|
+
import { defaultCliDependencies, } from "../dependencies.js";
|
|
6
|
+
import { isHeadless } from "../runtime/headless.js";
|
|
9
7
|
const MAX_UNDO_RECORDS = 20;
|
|
10
8
|
const UNDO_LOCK_STALE_AFTER_MS = 60_000;
|
|
11
9
|
const UNDO_LOCK_RETRY_DELAY_MS = 5;
|
|
12
10
|
const UNDO_LOCK_WAIT_TIMEOUT_MS = UNDO_LOCK_STALE_AFTER_MS + UNDO_LOCK_RETRY_DELAY_MS;
|
|
13
11
|
const undoLogQueues = new Map();
|
|
14
|
-
export function undoLogPath(home = homedir()
|
|
12
|
+
export function undoLogPath(home = homedir(), globalConfigDirectory = defaultCliDependencies.configStore
|
|
13
|
+
.GLOBAL_CONFIG_DIRECTORY) {
|
|
15
14
|
const configured = process.env.GJI_CONFIG_DIR;
|
|
16
|
-
return join(configured ? resolve(configured) : join(home,
|
|
15
|
+
return join(configured ? resolve(configured) : join(home, globalConfigDirectory), "undo-log.json");
|
|
17
16
|
}
|
|
18
|
-
export async function loadUndoRecords(home = homedir()
|
|
17
|
+
export async function loadUndoRecords(home = homedir(), globalConfigDirectory = defaultCliDependencies.configStore
|
|
18
|
+
.GLOBAL_CONFIG_DIRECTORY) {
|
|
19
19
|
try {
|
|
20
|
-
const parsed = JSON.parse(await readFile(undoLogPath(home), "utf8"));
|
|
20
|
+
const parsed = JSON.parse(await readFile(undoLogPath(home, globalConfigDirectory), "utf8"));
|
|
21
21
|
return Array.isArray(parsed) ? parsed.filter(isUndoRecord) : [];
|
|
22
22
|
}
|
|
23
23
|
catch {
|
|
24
24
|
return [];
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
export async function recordUndoOperation(op, repoRoot, worktrees, home = homedir()) {
|
|
27
|
+
export async function recordUndoOperation(op, repoRoot, worktrees, home = homedir(), runtime = defaultCliDependencies) {
|
|
28
|
+
const globalConfigDirectory = runtime.configStore.GLOBAL_CONFIG_DIRECTORY;
|
|
29
|
+
const { isDirtyWorktree, runGit } = runtime.git;
|
|
28
30
|
const entries = [];
|
|
29
31
|
for (const worktree of worktrees) {
|
|
30
32
|
try {
|
|
@@ -64,31 +66,33 @@ export async function recordUndoOperation(op, repoRoot, worktrees, home = homedi
|
|
|
64
66
|
entries,
|
|
65
67
|
};
|
|
66
68
|
return enqueueUndoLogWrite(home, async () => {
|
|
67
|
-
const existing = await loadUndoRecords(home);
|
|
68
|
-
await writeUndoRecords(home, [record, ...existing].slice(0, MAX_UNDO_RECORDS));
|
|
69
|
+
const existing = await loadUndoRecords(home, globalConfigDirectory);
|
|
70
|
+
await writeUndoRecords(home, [record, ...existing].slice(0, MAX_UNDO_RECORDS), globalConfigDirectory);
|
|
69
71
|
return record;
|
|
70
|
-
});
|
|
72
|
+
}, globalConfigDirectory);
|
|
71
73
|
}
|
|
72
|
-
export async function finalizeUndoOperation(record, removedWorktrees, home = homedir()
|
|
74
|
+
export async function finalizeUndoOperation(record, removedWorktrees, home = homedir(), globalConfigDirectory = defaultCliDependencies.configStore
|
|
75
|
+
.GLOBAL_CONFIG_DIRECTORY) {
|
|
73
76
|
const removedPaths = new Set(removedWorktrees.map((worktree) => worktree.path));
|
|
74
77
|
await enqueueUndoLogWrite(home, async () => {
|
|
75
|
-
const records = await loadUndoRecords(home);
|
|
78
|
+
const records = await loadUndoRecords(home, globalConfigDirectory);
|
|
76
79
|
const remaining = records.flatMap((candidate) => {
|
|
77
80
|
if (candidate.id !== record.id)
|
|
78
81
|
return [candidate];
|
|
79
82
|
const entries = candidate.entries.filter((entry) => removedPaths.has(entry.path));
|
|
80
83
|
return entries.length === 0 ? [] : [{ ...candidate, entries }];
|
|
81
84
|
});
|
|
82
|
-
await writeUndoRecords(home, remaining);
|
|
83
|
-
});
|
|
85
|
+
await writeUndoRecords(home, remaining, globalConfigDirectory);
|
|
86
|
+
}, globalConfigDirectory);
|
|
84
87
|
}
|
|
85
|
-
export async function restoreUndoRecord(record, home = homedir()) {
|
|
88
|
+
export async function restoreUndoRecord(record, home = homedir(), runtime = defaultCliDependencies) {
|
|
89
|
+
const globalConfigDirectory = runtime.configStore.GLOBAL_CONFIG_DIRECTORY;
|
|
86
90
|
const restored = [];
|
|
87
91
|
const failed = [];
|
|
88
92
|
const unresolved = [];
|
|
89
93
|
for (const entry of record.entries) {
|
|
90
94
|
try {
|
|
91
|
-
const upstreamFailure = await restoreUndoEntry(record.repoRoot, entry);
|
|
95
|
+
const upstreamFailure = await restoreUndoEntry(record.repoRoot, entry, runtime.git.runGit);
|
|
92
96
|
restored.push(entry);
|
|
93
97
|
if (upstreamFailure) {
|
|
94
98
|
failed.push({ ...entry, message: upstreamFailure });
|
|
@@ -101,7 +105,7 @@ export async function restoreUndoRecord(record, home = homedir()) {
|
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
await enqueueUndoLogWrite(home, async () => {
|
|
104
|
-
const records = await loadUndoRecords(home);
|
|
108
|
+
const records = await loadUndoRecords(home, globalConfigDirectory);
|
|
105
109
|
const remaining = records.flatMap((candidate) => {
|
|
106
110
|
if (candidate.id !== record.id)
|
|
107
111
|
return [candidate];
|
|
@@ -109,14 +113,17 @@ export async function restoreUndoRecord(record, home = homedir()) {
|
|
|
109
113
|
return [];
|
|
110
114
|
return [{ ...candidate, entries: unresolved }];
|
|
111
115
|
});
|
|
112
|
-
await writeUndoRecords(home, remaining);
|
|
113
|
-
});
|
|
116
|
+
await writeUndoRecords(home, remaining, globalConfigDirectory);
|
|
117
|
+
}, globalConfigDirectory);
|
|
114
118
|
return { restored, failed };
|
|
115
119
|
}
|
|
116
120
|
export async function runUndoCommand(options) {
|
|
117
|
-
|
|
121
|
+
const runtime = options.runtime ?? defaultCliDependencies;
|
|
122
|
+
const globalConfigDirectory = runtime.configStore.GLOBAL_CONFIG_DIRECTORY;
|
|
123
|
+
const { detectRepository } = runtime.repositoryContext;
|
|
124
|
+
if (await hasMalformedUndoLog(globalConfigDirectory))
|
|
118
125
|
options.stderr("Warning: undo journal is invalid; starting with an empty journal\n");
|
|
119
|
-
const records = await loadUndoRecords();
|
|
126
|
+
const records = await loadUndoRecords(homedir(), globalConfigDirectory);
|
|
120
127
|
if (options.list) {
|
|
121
128
|
if (options.json)
|
|
122
129
|
options.stdout(`${JSON.stringify(records, null, 2)}\n`);
|
|
@@ -167,7 +174,7 @@ export async function runUndoCommand(options) {
|
|
|
167
174
|
}
|
|
168
175
|
if (!record)
|
|
169
176
|
return emitUndoError(options, `undo record not found: ${options.id}`);
|
|
170
|
-
const result = await restoreUndoRecord(record);
|
|
177
|
+
const result = await restoreUndoRecord(record, homedir(), runtime);
|
|
171
178
|
if (options.json)
|
|
172
179
|
options.stdout(`${JSON.stringify({ restored: result.restored.map((entry) => ({ branch: entry.branch, path: entry.path })), failed: result.failed.map((entry) => ({ branch: entry.branch, path: entry.path, error: entry.message })) }, null, 2)}\n`);
|
|
173
180
|
else {
|
|
@@ -181,9 +188,10 @@ export async function runUndoCommand(options) {
|
|
|
181
188
|
}
|
|
182
189
|
return result.failed.length === 0 ? 0 : 1;
|
|
183
190
|
}
|
|
184
|
-
async function hasMalformedUndoLog(
|
|
191
|
+
async function hasMalformedUndoLog(globalConfigDirectory = defaultCliDependencies.configStore
|
|
192
|
+
.GLOBAL_CONFIG_DIRECTORY) {
|
|
185
193
|
try {
|
|
186
|
-
const parsed = JSON.parse(await readFile(undoLogPath(), "utf8"));
|
|
194
|
+
const parsed = JSON.parse(await readFile(undoLogPath(homedir(), globalConfigDirectory), "utf8"));
|
|
187
195
|
return (!Array.isArray(parsed) || parsed.some((entry) => !isUndoRecord(entry)));
|
|
188
196
|
}
|
|
189
197
|
catch (error) {
|
|
@@ -192,7 +200,7 @@ async function hasMalformedUndoLog() {
|
|
|
192
200
|
error.code !== "ENOENT");
|
|
193
201
|
}
|
|
194
202
|
}
|
|
195
|
-
async function restoreUndoEntry(repoRoot, entry) {
|
|
203
|
+
async function restoreUndoEntry(repoRoot, entry, runGit) {
|
|
196
204
|
try {
|
|
197
205
|
await access(entry.path);
|
|
198
206
|
throw new Error(`path already exists: ${entry.path}`);
|
|
@@ -203,7 +211,7 @@ async function restoreUndoEntry(repoRoot, entry) {
|
|
|
203
211
|
throw error;
|
|
204
212
|
}
|
|
205
213
|
if (entry.branch === null) {
|
|
206
|
-
await assertCommitExists(repoRoot, entry.headSha);
|
|
214
|
+
await assertCommitExists(repoRoot, entry.headSha, runGit);
|
|
207
215
|
await runGit(repoRoot, [
|
|
208
216
|
"worktree",
|
|
209
217
|
"add",
|
|
@@ -242,7 +250,7 @@ async function restoreUndoEntry(repoRoot, entry) {
|
|
|
242
250
|
throw new Error(`branch ${entry.branch} already tracks ${existingUpstream}; refusing to overwrite it`);
|
|
243
251
|
}
|
|
244
252
|
else {
|
|
245
|
-
await assertCommitExists(repoRoot, entry.headSha);
|
|
253
|
+
await assertCommitExists(repoRoot, entry.headSha, runGit);
|
|
246
254
|
await runGit(repoRoot, ["branch", entry.branch, entry.headSha]);
|
|
247
255
|
}
|
|
248
256
|
try {
|
|
@@ -276,7 +284,7 @@ async function restoreUndoEntry(repoRoot, entry) {
|
|
|
276
284
|
}
|
|
277
285
|
return null;
|
|
278
286
|
}
|
|
279
|
-
async function assertCommitExists(repoRoot, headSha) {
|
|
287
|
+
async function assertCommitExists(repoRoot, headSha, runGit) {
|
|
280
288
|
try {
|
|
281
289
|
await runGit(repoRoot, ["cat-file", "-e", `${headSha}^{commit}`]);
|
|
282
290
|
}
|
|
@@ -284,8 +292,9 @@ async function assertCommitExists(repoRoot, headSha) {
|
|
|
284
292
|
throw new Error("commit no longer exists (gc'd) — cannot restore");
|
|
285
293
|
}
|
|
286
294
|
}
|
|
287
|
-
async function enqueueUndoLogWrite(home, operation
|
|
288
|
-
|
|
295
|
+
async function enqueueUndoLogWrite(home, operation, globalConfigDirectory = defaultCliDependencies.configStore
|
|
296
|
+
.GLOBAL_CONFIG_DIRECTORY) {
|
|
297
|
+
const path = undoLogPath(home, globalConfigDirectory);
|
|
289
298
|
await mkdir(dirname(path), { recursive: true });
|
|
290
299
|
const previous = undoLogQueues.get(path) ?? Promise.resolve();
|
|
291
300
|
const runLocked = async () => {
|
|
@@ -332,8 +341,9 @@ async function acquireUndoLogLock(path) {
|
|
|
332
341
|
}
|
|
333
342
|
throw new Error("timed out waiting for the undo journal lock");
|
|
334
343
|
}
|
|
335
|
-
async function writeUndoRecords(home, records
|
|
336
|
-
|
|
344
|
+
async function writeUndoRecords(home, records, globalConfigDirectory = defaultCliDependencies.configStore
|
|
345
|
+
.GLOBAL_CONFIG_DIRECTORY) {
|
|
346
|
+
const path = undoLogPath(home, globalConfigDirectory);
|
|
337
347
|
await mkdir(dirname(path), { recursive: true });
|
|
338
348
|
const temporaryPath = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
339
349
|
try {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { type NavigationRepository } from "
|
|
2
|
-
import { type QueryWorktreePullRequests } from "
|
|
1
|
+
import { type NavigationRepository } from "../../presentation/terminal/navigation.js";
|
|
2
|
+
import { type QueryWorktreePullRequests } from "../../presentation/worktree/picker.js";
|
|
3
|
+
import { type CliRuntime } from "../dependencies.js";
|
|
3
4
|
export interface WarpCommandOptions {
|
|
4
5
|
branch?: string;
|
|
5
6
|
cwd: string;
|
|
6
7
|
json?: boolean;
|
|
7
8
|
queryPullRequests?: QueryWorktreePullRequests;
|
|
9
|
+
runtime?: CliRuntime<"history" | "repositoryContext" | "repositoryRegistry" | "worktrees" | "worktreeCatalog">;
|
|
8
10
|
stderr: (chunk: string) => void;
|
|
9
11
|
stdout: (chunk: string) => void;
|
|
10
12
|
}
|
|
@@ -21,5 +23,6 @@ export declare function resolveWarpTarget(options: {
|
|
|
21
23
|
excludeRepoRoot?: string;
|
|
22
24
|
json?: boolean;
|
|
23
25
|
queryPullRequests?: QueryWorktreePullRequests;
|
|
26
|
+
runtime?: CliRuntime<"history" | "repositoryContext" | "repositoryRegistry" | "worktrees" | "worktreeCatalog">;
|
|
24
27
|
stderr: (chunk: string) => void;
|
|
25
28
|
}): Promise<WarpTarget | null>;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { listRegisteredWorktreeSources } from "./worktree-sources.js";
|
|
1
|
+
import { listRegisteredWorktreeSources } from "../../application/worktree/sources.js";
|
|
2
|
+
import { resolveWorktreeQuery } from "../../domain/worktree/matching.js";
|
|
3
|
+
import { writeShellOutput } from "../../presentation/shell/handoff.js";
|
|
4
|
+
import { createNavigationRepository, createNavigationTarget, } from "../../presentation/terminal/navigation.js";
|
|
5
|
+
import { buildWorktreePromptEntries, promptForSingleWorktree, } from "../../presentation/worktree/picker.js";
|
|
6
|
+
import { defaultCliDependencies, withPullRequestQueries, } from "../dependencies.js";
|
|
7
|
+
import { isHeadless } from "../runtime/headless.js";
|
|
9
8
|
const WARP_OUTPUT_FILE_ENV = "GJI_WARP_OUTPUT_FILE";
|
|
10
9
|
export async function runWarpCommand(options) {
|
|
11
10
|
return runWarpNavigate(options);
|
|
12
11
|
}
|
|
13
12
|
async function runWarpNavigate(options) {
|
|
13
|
+
const runtime = options.runtime ?? defaultCliDependencies;
|
|
14
|
+
const { recordWorktreeUsage } = runtime.history;
|
|
14
15
|
if ((isHeadless() || options.json) && !options.branch) {
|
|
15
16
|
const message = "branch argument is required";
|
|
16
17
|
if (options.json) {
|
|
@@ -26,6 +27,7 @@ async function runWarpNavigate(options) {
|
|
|
26
27
|
commandName: "gji warp",
|
|
27
28
|
json: options.json,
|
|
28
29
|
queryPullRequests: options.queryPullRequests,
|
|
30
|
+
runtime,
|
|
29
31
|
});
|
|
30
32
|
if (!target)
|
|
31
33
|
return 1;
|
|
@@ -40,6 +42,14 @@ async function runWarpNavigate(options) {
|
|
|
40
42
|
}
|
|
41
43
|
export async function resolveWarpTarget(options) {
|
|
42
44
|
const cmd = options.commandName ?? "gji";
|
|
45
|
+
const runtime = options.runtime ?? defaultCliDependencies;
|
|
46
|
+
const { detectRepository } = runtime.repositoryContext;
|
|
47
|
+
const { loadRegistry } = runtime.repositoryRegistry;
|
|
48
|
+
const sourceDependencies = {
|
|
49
|
+
...runtime.repositoryContext,
|
|
50
|
+
...runtime.repositoryRegistry,
|
|
51
|
+
...runtime.worktrees,
|
|
52
|
+
};
|
|
43
53
|
const emitError = (message, hint) => {
|
|
44
54
|
if (options.json) {
|
|
45
55
|
options.stderr(`${JSON.stringify({ error: message }, null, 2)}\n`);
|
|
@@ -56,7 +66,7 @@ export async function resolveWarpTarget(options) {
|
|
|
56
66
|
return null;
|
|
57
67
|
}
|
|
58
68
|
let skippedRegisteredRepos = 0;
|
|
59
|
-
const allItems = (await listRegisteredWorktreeSources(options.cwd, () => {
|
|
69
|
+
const allItems = (await listRegisteredWorktreeSources(options.cwd, sourceDependencies, () => {
|
|
60
70
|
skippedRegisteredRepos++;
|
|
61
71
|
})).filter((item) => item.repoRoot !== options.excludeRepoRoot);
|
|
62
72
|
if (allItems.length === 0) {
|
|
@@ -87,7 +97,7 @@ export async function resolveWarpTarget(options) {
|
|
|
87
97
|
}
|
|
88
98
|
const promptEntries = await buildWorktreePromptEntries(promptSources, {
|
|
89
99
|
metadata: "fast",
|
|
90
|
-
|
|
100
|
+
catalog: withPullRequestQueries(runtime, options.queryPullRequests),
|
|
91
101
|
});
|
|
92
102
|
const path = await promptForWarpTarget(promptEntries);
|
|
93
103
|
if (!path) {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { WorktreeCatalogDependencies } from "../application/worktree/catalog.js";
|
|
2
|
+
import type { ContextCardDependencies } from "../application/worktree/context-card.js";
|
|
3
|
+
import { validateSyncFilePattern } from "../infrastructure/filesystem/file-sync.js";
|
|
4
|
+
import { isDirtyWorktree, readWorktreeHealth } from "../infrastructure/git/health.js";
|
|
5
|
+
import { isBranchMergedInto, readBranchLastCommitTimestamp, resolveRemoteBase, resolveRemoteDefaultBranch } from "../infrastructure/git/refs.js";
|
|
6
|
+
import { openBrowser } from "../infrastructure/integrations/browser.js";
|
|
7
|
+
import { defaultSpawnEditor, EDITORS } from "../infrastructure/integrations/editor.js";
|
|
8
|
+
import { GLOBAL_CONFIG_DIRECTORY, GLOBAL_CONFIG_FILE_PATH, KNOWN_CONFIG_KEYS, KNOWN_GLOBAL_CONFIG_KEYS, loadConfig, loadGlobalConfig, parseConfigValue, saveGlobalConfig, saveLocalConfig, unsetGlobalConfigKey, updateGlobalConfigKey } from "../infrastructure/persistence/config.js";
|
|
9
|
+
import { appendHistory, loadHistory, recordWorktreeUsage } from "../infrastructure/persistence/history.js";
|
|
10
|
+
import { assignWorktreeSlot, getWorktreeSlot, loadSlots, releaseWorktreeSlot } from "../infrastructure/persistence/slots.js";
|
|
11
|
+
import { clearTask, readTask, writeTask } from "../infrastructure/persistence/task.js";
|
|
12
|
+
import { extractHooks, runHook } from "../infrastructure/process/hooks.js";
|
|
13
|
+
import { loadRegistry, REGISTRY_FILE_PATH, registerRepo, removeMissingRegistryEntries } from "../infrastructure/repository/registry.js";
|
|
14
|
+
import { readWorktreeInfo, readWorktreeInfos, serializeWorktreeInfo } from "../infrastructure/worktree/info.js";
|
|
15
|
+
import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isSubmoduleWorktreeRemovalError, isWorktreeDeletionError, isWorktreeForceRemovalError, removeWorktree } from "../infrastructure/worktree/lifecycle.js";
|
|
16
|
+
import type { DependencyBootstrapPort, WorktreeBootstrapPort } from "../ports/bootstrap.js";
|
|
17
|
+
import type { ConfigPort } from "../ports/config.js";
|
|
18
|
+
import type { GitCommandPort } from "../ports/git.js";
|
|
19
|
+
import type { PullRequestPort } from "../ports/pull-requests.js";
|
|
20
|
+
import type { RepositoryContextPort, RepositoryRefPort, RepositoryRegistryPort, WorktreePort } from "../ports/repository.js";
|
|
21
|
+
import { formatLastCommit, formatRelativeAge, formatUpstreamState } from "../presentation/worktree/format.js";
|
|
22
|
+
export interface CliDependencies {
|
|
23
|
+
config: ConfigPort;
|
|
24
|
+
repositoryContext: RepositoryContextPort;
|
|
25
|
+
repositoryRefs: RepositoryRefPort;
|
|
26
|
+
repositoryRegistry: RepositoryRegistryPort;
|
|
27
|
+
worktrees: WorktreePort;
|
|
28
|
+
worktreeCatalog: WorktreeCatalogDependencies;
|
|
29
|
+
contextCard: ContextCardDependencies;
|
|
30
|
+
pullRequests: PullRequestPort;
|
|
31
|
+
history: {
|
|
32
|
+
recordWorktreeUsage: typeof recordWorktreeUsage;
|
|
33
|
+
};
|
|
34
|
+
slots: {
|
|
35
|
+
getWorktreeSlot: typeof getWorktreeSlot;
|
|
36
|
+
loadSlots: typeof loadSlots;
|
|
37
|
+
assignWorktreeSlot: typeof assignWorktreeSlot;
|
|
38
|
+
releaseWorktreeSlot: typeof releaseWorktreeSlot;
|
|
39
|
+
};
|
|
40
|
+
hooks: {
|
|
41
|
+
extractHooks: typeof extractHooks;
|
|
42
|
+
runHook: typeof runHook;
|
|
43
|
+
};
|
|
44
|
+
git: GitCommandPort & {
|
|
45
|
+
isDirtyWorktree: typeof isDirtyWorktree;
|
|
46
|
+
readWorktreeHealth: typeof readWorktreeHealth;
|
|
47
|
+
isBranchMergedInto: typeof isBranchMergedInto;
|
|
48
|
+
readBranchLastCommitTimestamp: typeof readBranchLastCommitTimestamp;
|
|
49
|
+
resolveRemoteBase: typeof resolveRemoteBase;
|
|
50
|
+
resolveRemoteDefaultBranch: typeof resolveRemoteDefaultBranch;
|
|
51
|
+
};
|
|
52
|
+
configStore: {
|
|
53
|
+
loadConfig: typeof loadConfig;
|
|
54
|
+
loadGlobalConfig: typeof loadGlobalConfig;
|
|
55
|
+
saveGlobalConfig: typeof saveGlobalConfig;
|
|
56
|
+
saveLocalConfig: typeof saveLocalConfig;
|
|
57
|
+
updateGlobalConfigKey: typeof updateGlobalConfigKey;
|
|
58
|
+
parseConfigValue: typeof parseConfigValue;
|
|
59
|
+
unsetGlobalConfigKey: typeof unsetGlobalConfigKey;
|
|
60
|
+
GLOBAL_CONFIG_FILE_PATH: typeof GLOBAL_CONFIG_FILE_PATH;
|
|
61
|
+
GLOBAL_CONFIG_DIRECTORY: typeof GLOBAL_CONFIG_DIRECTORY;
|
|
62
|
+
CONFIG_FILE_NAME: typeof import("../infrastructure/persistence/config.js").CONFIG_FILE_NAME;
|
|
63
|
+
KNOWN_CONFIG_KEYS: typeof KNOWN_CONFIG_KEYS;
|
|
64
|
+
KNOWN_GLOBAL_CONFIG_KEYS: typeof KNOWN_GLOBAL_CONFIG_KEYS;
|
|
65
|
+
};
|
|
66
|
+
tasks: {
|
|
67
|
+
readTask: typeof readTask;
|
|
68
|
+
writeTask: typeof writeTask;
|
|
69
|
+
clearTask: typeof clearTask;
|
|
70
|
+
};
|
|
71
|
+
historyStore: {
|
|
72
|
+
loadHistory: typeof loadHistory;
|
|
73
|
+
appendHistory: typeof appendHistory;
|
|
74
|
+
};
|
|
75
|
+
registry: {
|
|
76
|
+
loadRegistry: typeof loadRegistry;
|
|
77
|
+
registerRepo: typeof registerRepo;
|
|
78
|
+
REGISTRY_FILE_PATH: typeof REGISTRY_FILE_PATH;
|
|
79
|
+
removeMissingRegistryEntries: typeof removeMissingRegistryEntries;
|
|
80
|
+
};
|
|
81
|
+
worktreeLifecycle: {
|
|
82
|
+
deleteBranch: typeof deleteBranch;
|
|
83
|
+
forceDeleteBranch: typeof forceDeleteBranch;
|
|
84
|
+
forceRemoveWorktree: typeof forceRemoveWorktree;
|
|
85
|
+
removeWorktree: typeof removeWorktree;
|
|
86
|
+
isBranchUnmergedError: typeof isBranchUnmergedError;
|
|
87
|
+
isSubmoduleWorktreeRemovalError: typeof isSubmoduleWorktreeRemovalError;
|
|
88
|
+
isWorktreeDeletionError: typeof isWorktreeDeletionError;
|
|
89
|
+
isWorktreeForceRemovalError: typeof isWorktreeForceRemovalError;
|
|
90
|
+
};
|
|
91
|
+
worktreeInfo: {
|
|
92
|
+
readWorktreeInfo: typeof readWorktreeInfo;
|
|
93
|
+
readWorktreeInfos: typeof readWorktreeInfos;
|
|
94
|
+
serializeWorktreeInfo: typeof serializeWorktreeInfo;
|
|
95
|
+
formatLastCommit: typeof formatLastCommit;
|
|
96
|
+
formatRelativeAge: typeof formatRelativeAge;
|
|
97
|
+
formatUpstreamState: typeof formatUpstreamState;
|
|
98
|
+
};
|
|
99
|
+
bootstrap: {
|
|
100
|
+
bootstrapWorktree: WorktreeBootstrapPort["bootstrapWorktree"];
|
|
101
|
+
} & DependencyBootstrapPort;
|
|
102
|
+
integrations: {
|
|
103
|
+
openBrowser: typeof openBrowser;
|
|
104
|
+
defaultSpawnEditor: typeof defaultSpawnEditor;
|
|
105
|
+
EDITORS: typeof EDITORS;
|
|
106
|
+
};
|
|
107
|
+
filesystem: {
|
|
108
|
+
validateSyncFilePattern: typeof validateSyncFilePattern;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export type CliRuntime<Keys extends keyof CliDependencies> = Pick<CliDependencies, Keys>;
|
|
112
|
+
export declare function createCliDependencies(): CliDependencies;
|
|
113
|
+
export declare const defaultCliDependencies: CliDependencies;
|
|
114
|
+
export declare function withPullRequestQueries(dependencies: CliRuntime<"worktreeCatalog">, queryPullRequests?: WorktreeCatalogDependencies["queryPullRequests"], queryRepositoryPullRequests?: WorktreeCatalogDependencies["queryRepositoryPullRequests"]): WorktreeCatalogDependencies;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { prepareDependencyBootstrap, previewDependencyBootstrap, resolveDependencyBootstrapMode, } from "../infrastructure/bootstrap/dependency-bootstrap.js";
|
|
2
|
+
import { validateSyncFilePattern } from "../infrastructure/filesystem/file-sync.js";
|
|
3
|
+
import { isDirtyWorktree, readWorktreeHealth, } from "../infrastructure/git/health.js";
|
|
4
|
+
import { isBranchMergedInto, readBranchLastCommitTimestamp, resolveRemoteBase, resolveRemoteDefaultBranch, } from "../infrastructure/git/refs.js";
|
|
5
|
+
import { runGit, runGitRaw } from "../infrastructure/git/runner.js";
|
|
6
|
+
import { openBrowser } from "../infrastructure/integrations/browser.js";
|
|
7
|
+
import { defaultSpawnEditor, EDITORS, } from "../infrastructure/integrations/editor.js";
|
|
8
|
+
import { createPullRequestQuery } from "../infrastructure/integrations/pull-requests.js";
|
|
9
|
+
import { CONFIG_FILE_NAME, GLOBAL_CONFIG_DIRECTORY, GLOBAL_CONFIG_FILE_PATH, KNOWN_CONFIG_KEYS, KNOWN_GLOBAL_CONFIG_KEYS, loadConfig, loadGlobalConfig, parseConfigValue, saveGlobalConfig, saveLocalConfig, unsetGlobalConfigKey, updateGlobalConfigKey, } from "../infrastructure/persistence/config.js";
|
|
10
|
+
import { appendHistory, loadHistory, recordWorktreeUsage, } from "../infrastructure/persistence/history.js";
|
|
11
|
+
import { assignWorktreeSlot, getWorktreeSlot, loadSlots, releaseWorktreeSlot, } from "../infrastructure/persistence/slots.js";
|
|
12
|
+
import { clearTask, readTask, writeTask, } from "../infrastructure/persistence/task.js";
|
|
13
|
+
import { extractHooks, runHook } from "../infrastructure/process/hooks.js";
|
|
14
|
+
import { configPort, repositoryContextPort, repositoryRefPort, repositoryRegistryPort, worktreePort, } from "../infrastructure/repository/adapters.js";
|
|
15
|
+
import { loadRegistry, REGISTRY_FILE_PATH, registerRepo, removeMissingRegistryEntries, } from "../infrastructure/repository/registry.js";
|
|
16
|
+
import { bootstrapWorktree } from "../infrastructure/worktree/bootstrap.js";
|
|
17
|
+
import { readWorktreeInfo, readWorktreeInfos, serializeWorktreeInfo, } from "../infrastructure/worktree/info.js";
|
|
18
|
+
import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isSubmoduleWorktreeRemovalError, isWorktreeDeletionError, isWorktreeForceRemovalError, removeWorktree, } from "../infrastructure/worktree/lifecycle.js";
|
|
19
|
+
import { formatLastCommit, formatRelativeAge, formatUpstreamState, } from "../presentation/worktree/format.js";
|
|
20
|
+
export function createCliDependencies() {
|
|
21
|
+
const pullRequests = createPullRequestQuery();
|
|
22
|
+
return {
|
|
23
|
+
config: configPort,
|
|
24
|
+
repositoryContext: repositoryContextPort,
|
|
25
|
+
repositoryRefs: repositoryRefPort,
|
|
26
|
+
repositoryRegistry: repositoryRegistryPort,
|
|
27
|
+
worktrees: worktreePort,
|
|
28
|
+
worktreeCatalog: {
|
|
29
|
+
loadHistory: () => loadHistory(),
|
|
30
|
+
readTask,
|
|
31
|
+
readWorktreeInfos,
|
|
32
|
+
queryPullRequests: pullRequests.listOpenPullRequests,
|
|
33
|
+
queryRepositoryPullRequests: pullRequests.listOpenPullRequestsForRepository,
|
|
34
|
+
},
|
|
35
|
+
contextCard: {
|
|
36
|
+
listWorktrees: worktreePort.listWorktrees,
|
|
37
|
+
readTask,
|
|
38
|
+
readWorktreeInfo,
|
|
39
|
+
},
|
|
40
|
+
pullRequests,
|
|
41
|
+
history: { recordWorktreeUsage },
|
|
42
|
+
slots: {
|
|
43
|
+
getWorktreeSlot,
|
|
44
|
+
loadSlots,
|
|
45
|
+
assignWorktreeSlot,
|
|
46
|
+
releaseWorktreeSlot,
|
|
47
|
+
},
|
|
48
|
+
hooks: { extractHooks, runHook },
|
|
49
|
+
git: {
|
|
50
|
+
runGit,
|
|
51
|
+
runGitRaw,
|
|
52
|
+
isDirtyWorktree,
|
|
53
|
+
readWorktreeHealth,
|
|
54
|
+
isBranchMergedInto,
|
|
55
|
+
readBranchLastCommitTimestamp,
|
|
56
|
+
resolveRemoteBase,
|
|
57
|
+
resolveRemoteDefaultBranch,
|
|
58
|
+
},
|
|
59
|
+
configStore: {
|
|
60
|
+
loadConfig,
|
|
61
|
+
loadGlobalConfig,
|
|
62
|
+
saveGlobalConfig,
|
|
63
|
+
saveLocalConfig,
|
|
64
|
+
updateGlobalConfigKey,
|
|
65
|
+
parseConfigValue,
|
|
66
|
+
unsetGlobalConfigKey,
|
|
67
|
+
GLOBAL_CONFIG_FILE_PATH,
|
|
68
|
+
GLOBAL_CONFIG_DIRECTORY,
|
|
69
|
+
CONFIG_FILE_NAME,
|
|
70
|
+
KNOWN_CONFIG_KEYS,
|
|
71
|
+
KNOWN_GLOBAL_CONFIG_KEYS,
|
|
72
|
+
},
|
|
73
|
+
tasks: { readTask, writeTask, clearTask },
|
|
74
|
+
historyStore: { loadHistory, appendHistory },
|
|
75
|
+
registry: {
|
|
76
|
+
loadRegistry,
|
|
77
|
+
registerRepo,
|
|
78
|
+
REGISTRY_FILE_PATH,
|
|
79
|
+
removeMissingRegistryEntries,
|
|
80
|
+
},
|
|
81
|
+
worktreeLifecycle: {
|
|
82
|
+
deleteBranch,
|
|
83
|
+
forceDeleteBranch,
|
|
84
|
+
forceRemoveWorktree,
|
|
85
|
+
removeWorktree,
|
|
86
|
+
isBranchUnmergedError,
|
|
87
|
+
isSubmoduleWorktreeRemovalError,
|
|
88
|
+
isWorktreeDeletionError,
|
|
89
|
+
isWorktreeForceRemovalError,
|
|
90
|
+
},
|
|
91
|
+
worktreeInfo: {
|
|
92
|
+
readWorktreeInfo,
|
|
93
|
+
readWorktreeInfos,
|
|
94
|
+
serializeWorktreeInfo,
|
|
95
|
+
formatLastCommit,
|
|
96
|
+
formatRelativeAge,
|
|
97
|
+
formatUpstreamState,
|
|
98
|
+
},
|
|
99
|
+
bootstrap: {
|
|
100
|
+
bootstrapWorktree,
|
|
101
|
+
resolveMode: resolveDependencyBootstrapMode,
|
|
102
|
+
preview: async (mode, context) => previewDependencyBootstrap(await prepareDependencyBootstrap(mode, context)),
|
|
103
|
+
},
|
|
104
|
+
integrations: { openBrowser, defaultSpawnEditor, EDITORS },
|
|
105
|
+
filesystem: { validateSyncFilePattern },
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export const defaultCliDependencies = createCliDependencies();
|
|
109
|
+
export function withPullRequestQueries(dependencies, queryPullRequests, queryRepositoryPullRequests) {
|
|
110
|
+
return {
|
|
111
|
+
...dependencies.worktreeCatalog,
|
|
112
|
+
queryPullRequests: queryPullRequests ?? dependencies.worktreeCatalog.queryPullRequests,
|
|
113
|
+
queryRepositoryPullRequests: queryRepositoryPullRequests ??
|
|
114
|
+
(queryPullRequests === undefined
|
|
115
|
+
? dependencies.worktreeCatalog.queryRepositoryPullRequests
|
|
116
|
+
: undefined),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { type HubCommandDependencies } from "./hub.js";
|
|
3
|
-
import { type PrOpenCommandDependencies } from "./pr-open.js";
|
|
2
|
+
import { type HubCommandDependencies } from "./commands/hub.js";
|
|
3
|
+
import { type PrOpenCommandDependencies } from "./commands/pr-open.js";
|
|
4
|
+
import { type CliDependencies } from "./dependencies.js";
|
|
4
5
|
export interface RunCliOptions {
|
|
5
6
|
columns?: number;
|
|
6
7
|
cwd?: string;
|
|
@@ -9,6 +10,7 @@ export interface RunCliOptions {
|
|
|
9
10
|
hubDependencies?: Partial<HubCommandDependencies>;
|
|
10
11
|
stderr?: (chunk: string) => void;
|
|
11
12
|
stdout?: (chunk: string) => void;
|
|
13
|
+
dependencies?: CliDependencies;
|
|
12
14
|
}
|
|
13
15
|
export interface RunCliResult {
|
|
14
16
|
exitCode: number;
|