@solaqua/gji 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +82 -496
  2. package/dist/bootstrap-output.js +0 -1
  3. package/dist/clean.js +2 -0
  4. package/dist/cli.d.ts +4 -0
  5. package/dist/cli.js +40 -4
  6. package/dist/context-card.d.ts +1 -0
  7. package/dist/context-card.js +25 -0
  8. package/dist/dependency-bootstrap.d.ts +10 -17
  9. package/dist/dependency-bootstrap.js +343 -108
  10. package/dist/dir-clone.d.ts +1 -2
  11. package/dist/dir-clone.js +303 -167
  12. package/dist/doctor.js +21 -0
  13. package/dist/done.js +2 -0
  14. package/dist/gji-bundle.mjs +1854 -1032
  15. package/dist/go.d.ts +1 -0
  16. package/dist/go.js +8 -0
  17. package/dist/hooks.d.ts +1 -0
  18. package/dist/hooks.js +7 -1
  19. package/dist/hub.d.ts +31 -0
  20. package/dist/hub.js +299 -0
  21. package/dist/ls.js +9 -1
  22. package/dist/new.d.ts +1 -0
  23. package/dist/new.js +9 -0
  24. package/dist/pr-open.js +2 -10
  25. package/dist/pull-requests.d.ts +1 -0
  26. package/dist/pull-requests.js +32 -3
  27. package/dist/remove.js +2 -0
  28. package/dist/repo.d.ts +1 -0
  29. package/dist/repo.js +4 -0
  30. package/dist/run-hook.js +2 -0
  31. package/dist/safe-destination.js +10 -0
  32. package/dist/shell-completion.js +11 -3
  33. package/dist/slots.d.ts +8 -0
  34. package/dist/slots.js +61 -0
  35. package/dist/status.d.ts +2 -0
  36. package/dist/status.js +9 -1
  37. package/dist/sync-directories.d.ts +0 -4
  38. package/dist/sync-directories.js +6 -26
  39. package/dist/task-command.d.ts +9 -0
  40. package/dist/task-command.js +29 -0
  41. package/dist/task.d.ts +9 -0
  42. package/dist/task.js +37 -0
  43. package/dist/terminal-text.d.ts +4 -0
  44. package/dist/terminal-text.js +72 -0
  45. package/dist/worktree-bootstrap.js +3 -2
  46. package/dist/worktree-info.d.ts +6 -1
  47. package/dist/worktree-info.js +14 -4
  48. package/dist/worktree-picker.d.ts +3 -3
  49. package/dist/worktree-picker.js +84 -82
  50. package/dist/worktree-sources.d.ts +1 -0
  51. package/dist/worktree-sources.js +57 -11
  52. package/man/man1/gji-back.1 +1 -1
  53. package/man/man1/gji-clean.1 +1 -1
  54. package/man/man1/gji-completion.1 +1 -1
  55. package/man/man1/gji-config.1 +1 -1
  56. package/man/man1/gji-doctor.1 +1 -1
  57. package/man/man1/gji-done.1 +1 -1
  58. package/man/man1/gji-go.1 +4 -1
  59. package/man/man1/gji-history.1 +1 -1
  60. package/man/man1/gji-init.1 +1 -1
  61. package/man/man1/gji-ls.1 +1 -1
  62. package/man/man1/gji-new.1 +4 -1
  63. package/man/man1/gji-open.1 +1 -1
  64. package/man/man1/gji-pr.1 +1 -1
  65. package/man/man1/gji-remove.1 +1 -1
  66. package/man/man1/gji-root.1 +1 -1
  67. package/man/man1/gji-run-hook.1 +1 -1
  68. package/man/man1/gji-status.1 +1 -1
  69. package/man/man1/gji-sync-files.1 +1 -1
  70. package/man/man1/gji-sync.1 +1 -1
  71. package/man/man1/gji-task.1 +16 -0
  72. package/man/man1/gji-undo.1 +1 -1
  73. package/man/man1/gji-warp.1 +1 -1
  74. package/man/man1/gji.1 +5 -1
  75. package/package.json +1 -1
  76. package/dist/clone-failure-store.d.ts +0 -18
  77. package/dist/clone-failure-store.js +0 -230
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.length === 0) {
69
- program.outputHelp();
70
- return { exitCode: 0 };
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
+ }
@@ -1,9 +1,8 @@
1
- import { type CloneFailureStore } from "./clone-failure-store.js";
2
1
  import { type CommandRunner } from "./command-runner.js";
3
2
  import type { DependencyBootstrapMode } from "./config.js";
4
3
  import { type CloneDirectory } from "./dir-clone.js";
5
4
  export type BootstrapKind = "dependency" | "build-cache" | "sync-file";
6
- export type BootstrapState = "seeded" | "repaired" | "installed" | "fallback" | "skipped" | "failed";
5
+ export type BootstrapState = "seeded" | "repaired" | "installed" | "repair-only" | "skipped" | "failed";
7
6
  export type BootstrapStrategy = "cow-then-repair" | "repair-only" | "install-only";
8
7
  export type BootstrapCommandRunner = CommandRunner;
9
8
  export interface BootstrapPreparationContext {
@@ -11,11 +10,14 @@ export interface BootstrapPreparationContext {
11
10
  sourceRoot: string;
12
11
  worktreePath: string;
13
12
  }
14
- export interface BootstrapExecutionContext {
13
+ interface BootstrapCommandExecutionContext {
15
14
  runCommand: BootstrapCommandRunner;
16
15
  stderr: (chunk: string) => void;
17
16
  stdout: (chunk: string) => void;
18
17
  }
18
+ export interface BootstrapExecutionContext extends BootstrapCommandExecutionContext {
19
+ input: BootstrapTargetInput;
20
+ }
19
21
  export interface BootstrapTarget {
20
22
  adapter: string;
21
23
  kind: BootstrapKind;
@@ -26,19 +28,13 @@ export interface BootstrapTarget {
26
28
  targetPath: string;
27
29
  repairCommand: string;
28
30
  repairState: "repaired" | "installed";
29
- existingBeforeBootstrap: boolean;
31
+ shell: boolean;
32
+ initialInput: Exclude<BootstrapTargetInput, "seed">;
30
33
  }
31
- export type BootstrapTargetOwnership = "adapter" | "syncDirs" | "empty" | "preserve";
34
+ export type BootstrapTargetInput = "clean" | "preserve" | "seed";
32
35
  export interface BootstrapRepairFailureContext {
36
+ input: BootstrapTargetInput;
33
37
  target: BootstrapTarget;
34
- ownership: BootstrapTargetOwnership;
35
- targetExistedBeforeRepair: boolean;
36
- }
37
- export interface BootstrapOutputMetadata {
38
- adapter: string;
39
- kind: BootstrapKind;
40
- target: string;
41
- repairCommand: string;
42
38
  }
43
39
  export interface BootstrapAdapter {
44
40
  readonly kind: BootstrapKind;
@@ -49,7 +45,6 @@ export interface BootstrapAdapter {
49
45
  seedPath(target: BootstrapTarget): string;
50
46
  repair(target: BootstrapTarget, context: BootstrapExecutionContext): Promise<void>;
51
47
  canSeed(target: BootstrapTarget): Promise<boolean>;
52
- output(target: BootstrapTarget): BootstrapOutputMetadata;
53
48
  shouldRetryAfterRepairFailure(context: BootstrapRepairFailureContext): boolean;
54
49
  cleanupAfterRepairFailure(context: BootstrapRepairFailureContext): Promise<void>;
55
50
  }
@@ -58,7 +53,6 @@ export interface DependencyBootstrapPlan {
58
53
  targets: readonly PlannedBootstrapTarget[];
59
54
  }
60
55
  export interface PlannedBootstrapTarget {
61
- adapter: BootstrapAdapter;
62
56
  target: BootstrapTarget;
63
57
  seedable: boolean;
64
58
  }
@@ -81,7 +75,6 @@ export interface DependencyBootstrapReport {
81
75
  }
82
76
  export interface DependencyBootstrapDependencies {
83
77
  cloneDirectory?: CloneDirectory;
84
- failureStore?: CloneFailureStore;
85
78
  runCommand?: BootstrapCommandRunner;
86
79
  stderr?: (chunk: string) => void;
87
80
  stdout?: (chunk: string) => void;
@@ -124,6 +117,6 @@ export declare function detectDependencyBootstrapCandidate(context: {
124
117
  }): Promise<DependencyBootstrapCandidate | null>;
125
118
  export declare function previewDependencyBootstrap(plan: DependencyBootstrapPlan): DependencyBootstrapPreview;
126
119
  export declare function executeDependencyBootstrap(plan: DependencyBootstrapPlan, options: DependencyBootstrapDependencies & {
127
- repoRoot: string;
128
120
  reporter: DependencyBootstrapReporter;
129
121
  }): Promise<DependencyBootstrapReport>;
122
+ export {};