@solaqua/gji 0.11.0 → 0.12.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 +82 -496
- package/dist/clean.js +2 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +40 -4
- package/dist/context-card.d.ts +1 -0
- package/dist/context-card.js +25 -0
- package/dist/doctor.js +21 -0
- package/dist/done.js +2 -0
- package/dist/gji-bundle.mjs +988 -350
- package/dist/go.d.ts +1 -0
- package/dist/go.js +8 -0
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.js +7 -1
- package/dist/hub.d.ts +31 -0
- package/dist/hub.js +287 -0
- package/dist/ls.js +9 -1
- package/dist/new.d.ts +1 -0
- package/dist/new.js +9 -0
- package/dist/pr-open.js +2 -10
- package/dist/pull-requests.d.ts +1 -0
- package/dist/pull-requests.js +32 -3
- package/dist/remove.js +2 -0
- package/dist/repo.d.ts +1 -0
- package/dist/repo.js +4 -0
- package/dist/run-hook.js +2 -0
- package/dist/shell-completion.js +11 -3
- package/dist/slots.d.ts +8 -0
- package/dist/slots.js +61 -0
- package/dist/status.d.ts +2 -0
- package/dist/status.js +9 -1
- package/dist/task-command.d.ts +9 -0
- package/dist/task-command.js +29 -0
- package/dist/task.d.ts +9 -0
- package/dist/task.js +37 -0
- package/dist/terminal-text.d.ts +4 -0
- package/dist/terminal-text.js +72 -0
- package/dist/worktree-bootstrap.js +3 -0
- package/dist/worktree-info.d.ts +6 -1
- package/dist/worktree-info.js +14 -4
- package/dist/worktree-picker.d.ts +3 -3
- package/dist/worktree-picker.js +71 -82
- package/dist/worktree-sources.d.ts +1 -0
- package/dist/worktree-sources.js +57 -11
- 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 +4 -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 +4 -1
- 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 +16 -0
- package/man/man1/gji-undo.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +5 -1
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import { type HubCommandDependencies } from "./hub.js";
|
|
2
3
|
import { type PrOpenCommandDependencies } from "./pr-open.js";
|
|
3
4
|
export interface RunCliOptions {
|
|
5
|
+
columns?: number;
|
|
4
6
|
cwd?: string;
|
|
7
|
+
now?: number;
|
|
5
8
|
prOpenDependencies?: Partial<PrOpenCommandDependencies>;
|
|
9
|
+
hubDependencies?: Partial<HubCommandDependencies>;
|
|
6
10
|
stderr?: (chunk: string) => void;
|
|
7
11
|
stdout?: (chunk: string) => void;
|
|
8
12
|
}
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import { runDoneCommand } from "./done.js";
|
|
|
10
10
|
import { runGoCommand } from "./go.js";
|
|
11
11
|
import { isHeadless } from "./headless.js";
|
|
12
12
|
import { runHistoryCommand } from "./history-command.js";
|
|
13
|
+
import { runHubCommand } from "./hub.js";
|
|
13
14
|
import { runInitCommand } from "./init.js";
|
|
14
15
|
import { runLsCommand } from "./ls.js";
|
|
15
16
|
import { runNewCommand } from "./new.js";
|
|
@@ -24,6 +25,7 @@ import { runHookCommand } from "./run-hook.js";
|
|
|
24
25
|
import { runStatusCommand } from "./status.js";
|
|
25
26
|
import { runSyncCommand } from "./sync.js";
|
|
26
27
|
import { runSyncFilesCommand } from "./sync-files-command.js";
|
|
28
|
+
import { runTaskCommand } from "./task-command.js";
|
|
27
29
|
import { runUndoCommand } from "./undo.js";
|
|
28
30
|
import { runWarpCommand } from "./warp.js";
|
|
29
31
|
export function createProgram() {
|
|
@@ -56,7 +58,7 @@ export async function runCli(argv, options = {}) {
|
|
|
56
58
|
const cwd = options.cwd ?? process.cwd();
|
|
57
59
|
const stdout = options.stdout ?? (() => undefined);
|
|
58
60
|
const stderr = options.stderr ?? (() => undefined);
|
|
59
|
-
if (shouldRegisterCurrentRepo(argv)) {
|
|
61
|
+
if (shouldRegisterCurrentRepo(argv) || isHubInvocation(argv)) {
|
|
60
62
|
await maybeRegisterCurrentRepo(cwd);
|
|
61
63
|
}
|
|
62
64
|
const program = createProgram();
|
|
@@ -65,9 +67,16 @@ export async function runCli(argv, options = {}) {
|
|
|
65
67
|
writeOut: stdout,
|
|
66
68
|
});
|
|
67
69
|
program.exitOverride();
|
|
68
|
-
if (argv
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
if (isHubInvocation(argv)) {
|
|
71
|
+
const exitCode = await runHubCommand({
|
|
72
|
+
columns: options.columns,
|
|
73
|
+
cwd,
|
|
74
|
+
json: argv.includes("--json"),
|
|
75
|
+
now: options.now,
|
|
76
|
+
stderr,
|
|
77
|
+
stdout,
|
|
78
|
+
}, options.hubDependencies);
|
|
79
|
+
return { exitCode };
|
|
71
80
|
}
|
|
72
81
|
try {
|
|
73
82
|
attachCommandActions(program, {
|
|
@@ -131,6 +140,9 @@ function shouldRegisterCurrentRepo(argv) {
|
|
|
131
140
|
"init",
|
|
132
141
|
].includes(command ?? ""));
|
|
133
142
|
}
|
|
143
|
+
function isHubInvocation(argv) {
|
|
144
|
+
return argv.length === 0 || (argv.length === 1 && argv[0] === "--json");
|
|
145
|
+
}
|
|
134
146
|
async function maybeRegisterCurrentRepo(cwd) {
|
|
135
147
|
try {
|
|
136
148
|
const { repoRoot } = await detectRepository(cwd);
|
|
@@ -149,6 +161,7 @@ function registerCommands(program) {
|
|
|
149
161
|
.option("--from-current", "base the new branch on the current worktree instead of the main worktree (cannot be combined with --detached)")
|
|
150
162
|
.option("--no-fetch", "skip refreshing the remote default branch before creating the new branch")
|
|
151
163
|
.option("--take", "move current uncommitted changes into the new worktree")
|
|
164
|
+
.option("--task <description>", "record the purpose of the new worktree")
|
|
152
165
|
.option("--copy", "copy current uncommitted changes instead of moving them (requires --take)")
|
|
153
166
|
.option("--open", "open the new worktree in an editor after creation")
|
|
154
167
|
.option("--editor <cli>", "editor CLI to use with --open (code, cursor, zed, …)")
|
|
@@ -221,6 +234,7 @@ function registerCommands(program) {
|
|
|
221
234
|
.description("resolve and jump to a worktree path")
|
|
222
235
|
.option("--root", "navigate to the main repository root")
|
|
223
236
|
.option("--print", "print the resolved worktree path explicitly")
|
|
237
|
+
.option("--quiet", "suppress the context card")
|
|
224
238
|
.option("--json", "emit JSON for an existing worktree destination")
|
|
225
239
|
.action(notImplemented("go"));
|
|
226
240
|
program
|
|
@@ -233,6 +247,12 @@ function registerCommands(program) {
|
|
|
233
247
|
.description("summarize repository and worktree health")
|
|
234
248
|
.option("--json", "print repository and worktree health as JSON")
|
|
235
249
|
.action(notImplemented("status"));
|
|
250
|
+
program
|
|
251
|
+
.command("task [task]")
|
|
252
|
+
.description("show or update the current worktree task")
|
|
253
|
+
.option("--clear", "clear the current worktree task")
|
|
254
|
+
.option("--json", "emit task metadata as JSON")
|
|
255
|
+
.action(notImplemented("task"));
|
|
236
256
|
program
|
|
237
257
|
.command("sync")
|
|
238
258
|
.description("fetch and update one or all worktrees")
|
|
@@ -329,6 +349,7 @@ function attachCommandActions(program, options) {
|
|
|
329
349
|
json: commandOptions.json,
|
|
330
350
|
open: commandOptions.open,
|
|
331
351
|
take: commandOptions.take,
|
|
352
|
+
task: commandOptions.task,
|
|
332
353
|
});
|
|
333
354
|
if (exitCode !== 0) {
|
|
334
355
|
throw commanderExit(exitCode);
|
|
@@ -492,6 +513,7 @@ function attachCommandActions(program, options) {
|
|
|
492
513
|
cwd: options.cwd,
|
|
493
514
|
json: commandOptions.json,
|
|
494
515
|
print: commandOptions.print,
|
|
516
|
+
quiet: commandOptions.quiet,
|
|
495
517
|
root: commandOptions.root,
|
|
496
518
|
stderr: options.stderr,
|
|
497
519
|
stdout: options.stdout,
|
|
@@ -524,6 +546,20 @@ function attachCommandActions(program, options) {
|
|
|
524
546
|
throw commanderExit(exitCode);
|
|
525
547
|
}
|
|
526
548
|
});
|
|
549
|
+
program.commands
|
|
550
|
+
.find((command) => command.name() === "task")
|
|
551
|
+
?.action(async (task, commandOptions) => {
|
|
552
|
+
const exitCode = await runTaskCommand({
|
|
553
|
+
clear: commandOptions.clear,
|
|
554
|
+
cwd: options.cwd,
|
|
555
|
+
json: commandOptions.json,
|
|
556
|
+
stderr: options.stderr,
|
|
557
|
+
task,
|
|
558
|
+
stdout: options.stdout,
|
|
559
|
+
});
|
|
560
|
+
if (exitCode !== 0)
|
|
561
|
+
throw commanderExit(exitCode);
|
|
562
|
+
});
|
|
527
563
|
program.commands
|
|
528
564
|
.find((command) => command.name() === "sync")
|
|
529
565
|
?.action(async (commandOptions) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderContextCard(worktreePath: string): Promise<string | null>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { listWorktrees } from "./repo.js";
|
|
2
|
+
import { readTask } from "./task.js";
|
|
3
|
+
import { readWorktreeInfo } from "./worktree-info.js";
|
|
4
|
+
export async function renderContextCard(worktreePath) {
|
|
5
|
+
const worktree = (await listWorktrees(worktreePath)).find((entry) => entry.path === worktreePath);
|
|
6
|
+
if (!worktree)
|
|
7
|
+
return null;
|
|
8
|
+
const info = await readWorktreeInfo(worktree);
|
|
9
|
+
const task = await readTask(worktreePath);
|
|
10
|
+
if (!task)
|
|
11
|
+
return null;
|
|
12
|
+
const rows = [`┌ ${info.branch ?? "(detached)"}`];
|
|
13
|
+
rows.push(`│ task ${task.task}`);
|
|
14
|
+
rows.push(`│ state ${formatState(info)}`);
|
|
15
|
+
if (info.lastCommitTimestamp !== null)
|
|
16
|
+
rows.push(`│ last ${formatLastCommit(info)}`);
|
|
17
|
+
rows.push("└");
|
|
18
|
+
return rows.join("\n");
|
|
19
|
+
}
|
|
20
|
+
function formatState(info) {
|
|
21
|
+
return `${info.status}${info.upstream.kind === "tracked" ? ` · ↑${info.upstream.ahead} ↓${info.upstream.behind}` : ""}`;
|
|
22
|
+
}
|
|
23
|
+
function formatLastCommit(info) {
|
|
24
|
+
return new Date(info.lastCommitTimestamp).toISOString();
|
|
25
|
+
}
|
package/dist/doctor.js
CHANGED
|
@@ -12,6 +12,7 @@ import { detectRepository } from "./repo.js";
|
|
|
12
12
|
import { loadRegistry, REGISTRY_FILE_PATH, removeMissingRegistryEntries, } from "./repo-registry.js";
|
|
13
13
|
import { resolveSupportedShell } from "./shell.js";
|
|
14
14
|
import { executableExists, hasShellIntegration, resolveCompletionPath, resolveShellConfigPath, } from "./shell-setup.js";
|
|
15
|
+
import { loadSlots } from "./slots.js";
|
|
15
16
|
const execFileAsync = promisify(execFile);
|
|
16
17
|
const MINIMUM_GIT_VERSION = { major: 2, minor: 17 };
|
|
17
18
|
export async function runDoctorCommand(options) {
|
|
@@ -82,10 +83,30 @@ async function collectDoctorInspection(cwd, home, shell) {
|
|
|
82
83
|
await checkWorktreeBase(repository, effectiveConfig, home),
|
|
83
84
|
registry.check,
|
|
84
85
|
await checkEditor(effectiveConfig),
|
|
86
|
+
await checkOrphanSlots(home),
|
|
85
87
|
],
|
|
86
88
|
missingRegistryPaths: registry.missingPaths,
|
|
87
89
|
};
|
|
88
90
|
}
|
|
91
|
+
async function checkOrphanSlots(home) {
|
|
92
|
+
const slots = await loadSlots(home);
|
|
93
|
+
const missing = (await Promise.all(Object.keys(slots).map(async (path) => {
|
|
94
|
+
try {
|
|
95
|
+
await access(path);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
}))).filter(Boolean).length;
|
|
102
|
+
return {
|
|
103
|
+
id: "slots",
|
|
104
|
+
message: missing === 0
|
|
105
|
+
? "worktree slots healthy"
|
|
106
|
+
: `${missing} orphaned worktree slot${missing === 1 ? "" : "s"}`,
|
|
107
|
+
status: "ok",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
89
110
|
function buildDoctorFixes(missingRegistryPaths) {
|
|
90
111
|
if (missingRegistryPaths.length === 0)
|
|
91
112
|
return [];
|
package/dist/done.js
CHANGED
|
@@ -7,6 +7,7 @@ import { loadHistory } from "./history.js";
|
|
|
7
7
|
import { extractHooks, runHook } from "./hooks.js";
|
|
8
8
|
import { detectRepository, listWorktrees } from "./repo.js";
|
|
9
9
|
import { writeShellOutput } from "./shell-handoff.js";
|
|
10
|
+
import { releaseWorktreeSlot } from "./slots.js";
|
|
10
11
|
import { finalizeUndoOperation, recordUndoOperation } from "./undo.js";
|
|
11
12
|
import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isWorktreeForceRemovalError, removeWorktree, } from "./worktree-management.js";
|
|
12
13
|
const DONE_OUTPUT_FILE_ENV = "GJI_DONE_OUTPUT_FILE";
|
|
@@ -122,6 +123,7 @@ export async function runDoneCommand(options) {
|
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
await finalizeUndoOperation(journal, [target]);
|
|
126
|
+
await releaseWorktreeSlot(target.path);
|
|
125
127
|
await runGit(repository.repoRoot, ["worktree", "prune"]).catch(() => undefined);
|
|
126
128
|
const shouldMove = options.branch === undefined || target.path === repository.currentRoot;
|
|
127
129
|
const movedTo = shouldMove
|