@solaqua/gji 0.6.2 → 0.7.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 (84) hide show
  1. package/README.md +26 -1
  2. package/dist/back.d.ts +1 -1
  3. package/dist/back.js +23 -17
  4. package/dist/clean.d.ts +1 -1
  5. package/dist/clean.js +44 -35
  6. package/dist/cli.d.ts +1 -1
  7. package/dist/cli.js +266 -165
  8. package/dist/completion.js +3 -3
  9. package/dist/config-command.js +5 -5
  10. package/dist/config.js +41 -35
  11. package/dist/conflict.d.ts +1 -1
  12. package/dist/conflict.js +14 -6
  13. package/dist/editor.js +29 -9
  14. package/dist/file-sync.d.ts +1 -0
  15. package/dist/file-sync.js +15 -11
  16. package/dist/git.d.ts +1 -1
  17. package/dist/git.js +21 -19
  18. package/dist/gji-bundle.mjs +1688 -865
  19. package/dist/go.d.ts +2 -2
  20. package/dist/go.js +39 -26
  21. package/dist/headless.js +1 -1
  22. package/dist/history-command.js +3 -3
  23. package/dist/history.js +12 -12
  24. package/dist/hooks.d.ts +3 -3
  25. package/dist/hooks.js +19 -19
  26. package/dist/index.js +13 -9
  27. package/dist/init.d.ts +5 -5
  28. package/dist/init.js +115 -103
  29. package/dist/install-prompt.d.ts +3 -3
  30. package/dist/install-prompt.js +57 -38
  31. package/dist/ls.d.ts +2 -2
  32. package/dist/ls.js +29 -29
  33. package/dist/new.d.ts +2 -2
  34. package/dist/new.js +97 -82
  35. package/dist/open.d.ts +2 -2
  36. package/dist/open.js +24 -21
  37. package/dist/package-manager.js +96 -45
  38. package/dist/pr.d.ts +2 -2
  39. package/dist/pr.js +47 -34
  40. package/dist/remove.d.ts +1 -1
  41. package/dist/remove.js +39 -27
  42. package/dist/repo-registry.js +14 -14
  43. package/dist/repo.js +29 -28
  44. package/dist/root.js +3 -3
  45. package/dist/run-hook.d.ts +6 -0
  46. package/dist/{trigger-hook.js → run-hook.js} +18 -8
  47. package/dist/shell-completion.d.ts +1 -1
  48. package/dist/shell-completion.js +67 -39
  49. package/dist/shell-handoff.js +2 -2
  50. package/dist/shell.d.ts +1 -1
  51. package/dist/shell.js +4 -4
  52. package/dist/status.d.ts +5 -5
  53. package/dist/status.js +23 -23
  54. package/dist/sync-files-command.d.ts +10 -0
  55. package/dist/sync-files-command.js +137 -0
  56. package/dist/sync.js +23 -15
  57. package/dist/warp.js +37 -33
  58. package/dist/worktree-info.d.ts +9 -9
  59. package/dist/worktree-info.js +31 -29
  60. package/dist/worktree-management.d.ts +1 -1
  61. package/dist/worktree-management.js +26 -11
  62. package/dist/worktree-prompts.js +5 -5
  63. package/man/man1/gji-back.1 +1 -1
  64. package/man/man1/gji-clean.1 +1 -1
  65. package/man/man1/gji-completion.1 +1 -1
  66. package/man/man1/gji-config.1 +1 -1
  67. package/man/man1/gji-go.1 +1 -1
  68. package/man/man1/gji-history.1 +1 -1
  69. package/man/man1/gji-init.1 +1 -1
  70. package/man/man1/gji-ls.1 +1 -1
  71. package/man/man1/gji-new.1 +1 -1
  72. package/man/man1/gji-open.1 +1 -1
  73. package/man/man1/gji-pr.1 +1 -1
  74. package/man/man1/gji-remove.1 +1 -1
  75. package/man/man1/gji-root.1 +1 -1
  76. package/man/man1/gji-run-hook.1 +9 -0
  77. package/man/man1/gji-status.1 +1 -1
  78. package/man/man1/gji-sync-files.1 +23 -0
  79. package/man/man1/gji-sync.1 +1 -1
  80. package/man/man1/gji-warp.1 +1 -1
  81. package/man/man1/gji.1 +10 -4
  82. package/package.json +8 -2
  83. package/dist/trigger-hook.d.ts +0 -6
  84. package/man/man1/gji-trigger-hook.1 +0 -9
package/dist/cli.js CHANGED
@@ -1,32 +1,33 @@
1
- import { createRequire } from 'node:module';
2
- import { Command } from 'commander';
3
- import updateNotifier from 'update-notifier';
4
- import { runBackCommand } from './back.js';
5
- import { runCleanCommand } from './clean.js';
6
- import { runHistoryCommand } from './history-command.js';
7
- import { runCompletionCommand } from './completion.js';
8
- import { runConfigCommand } from './config-command.js';
9
- import { runGoCommand } from './go.js';
10
- import { runOpenCommand } from './open.js';
11
- import { isHeadless } from './headless.js';
12
- import { runInitCommand } from './init.js';
13
- import { runLsCommand } from './ls.js';
14
- import { runNewCommand } from './new.js';
15
- import { runPrCommand } from './pr.js';
16
- import { runRemoveCommand } from './remove.js';
17
- import { registerRepo } from './repo-registry.js';
18
- import { detectRepository } from './repo.js';
19
- import { runRootCommand } from './root.js';
20
- import { runStatusCommand } from './status.js';
21
- import { runSyncCommand } from './sync.js';
22
- import { runTriggerHookCommand } from './trigger-hook.js';
23
- import { runWarpCommand } from './warp.js';
1
+ import { createRequire } from "node:module";
2
+ import { Command } from "commander";
3
+ import updateNotifier from "update-notifier";
4
+ import { runBackCommand } from "./back.js";
5
+ import { runCleanCommand } from "./clean.js";
6
+ import { runCompletionCommand } from "./completion.js";
7
+ import { runConfigCommand } from "./config-command.js";
8
+ import { runGoCommand } from "./go.js";
9
+ import { isHeadless } from "./headless.js";
10
+ import { runHistoryCommand } from "./history-command.js";
11
+ import { runInitCommand } from "./init.js";
12
+ import { runLsCommand } from "./ls.js";
13
+ import { runNewCommand } from "./new.js";
14
+ import { runOpenCommand } from "./open.js";
15
+ import { runPrCommand } from "./pr.js";
16
+ import { runRemoveCommand } from "./remove.js";
17
+ import { detectRepository } from "./repo.js";
18
+ import { registerRepo } from "./repo-registry.js";
19
+ import { runRootCommand } from "./root.js";
20
+ import { runHookCommand } from "./run-hook.js";
21
+ import { runStatusCommand } from "./status.js";
22
+ import { runSyncCommand } from "./sync.js";
23
+ import { runSyncFilesCommand } from "./sync-files-command.js";
24
+ import { runWarpCommand } from "./warp.js";
24
25
  export function createProgram() {
25
26
  const program = new Command();
26
27
  const packageMetadata = readPackageMetadata();
27
28
  program
28
- .name('gji')
29
- .description('Context switching without the mess.')
29
+ .name("gji")
30
+ .description("Context switching without the mess.")
30
31
  .version(packageMetadata.version)
31
32
  .showHelpAfterError()
32
33
  .showSuggestionAfterError();
@@ -35,10 +36,10 @@ export function createProgram() {
35
36
  }
36
37
  function readPackageMetadata() {
37
38
  const require = createRequire(import.meta.url);
38
- const packageJson = require('../package.json');
39
+ const packageJson = require("../package.json");
39
40
  return {
40
- name: typeof packageJson.name === 'string' ? packageJson.name : 'gji',
41
- version: typeof packageJson.version === 'string' ? packageJson.version : '0.0.0',
41
+ name: typeof packageJson.name === "string" ? packageJson.name : "gji",
42
+ version: typeof packageJson.version === "string" ? packageJson.version : "0.0.0",
42
43
  };
43
44
  }
44
45
  export async function runCli(argv, options = {}) {
@@ -59,7 +60,7 @@ export async function runCli(argv, options = {}) {
59
60
  }
60
61
  try {
61
62
  attachCommandActions(program, { cwd, stderr, stdout });
62
- await program.parseAsync(['node', 'gji', ...argv], { from: 'node' });
63
+ await program.parseAsync(["node", "gji", ...argv], { from: "node" });
63
64
  return { exitCode: 0 };
64
65
  }
65
66
  catch (error) {
@@ -81,19 +82,19 @@ async function maybeNotifyForUpdates(argv) {
81
82
  }
82
83
  }
83
84
  function shouldSkipUpdateNotification(argv) {
84
- return (argv.length === 0
85
- || argv.includes('--json')
86
- || argv.some(isHelpOrVersionArgument)
87
- || isHeadless()
88
- || process.stdout.isTTY !== true
89
- || process.stderr.isTTY !== true);
85
+ return (argv.length === 0 ||
86
+ argv.includes("--json") ||
87
+ argv.some(isHelpOrVersionArgument) ||
88
+ isHeadless() ||
89
+ process.stdout.isTTY !== true ||
90
+ process.stderr.isTTY !== true);
90
91
  }
91
92
  function isHelpOrVersionArgument(argument) {
92
- return (argument === '--help'
93
- || argument === '-h'
94
- || argument === 'help'
95
- || argument === '--version'
96
- || argument === '-V');
93
+ return (argument === "--help" ||
94
+ argument === "-h" ||
95
+ argument === "help" ||
96
+ argument === "--version" ||
97
+ argument === "-V");
97
98
  }
98
99
  function defaultNotifyForUpdates(pkg) {
99
100
  const notifier = updateNotifier({ pkg });
@@ -106,132 +107,163 @@ function maybeRegisterCurrentRepo(cwd) {
106
107
  }
107
108
  function registerCommands(program) {
108
109
  program
109
- .command('new [branch]')
110
- .description('create a new branch or detached linked worktree')
111
- .option('-f, --force', 'remove and recreate the worktree if the target path already exists')
112
- .option('--detached', 'create a detached worktree without a branch')
113
- .option('--open', 'open the new worktree in an editor after creation')
114
- .option('--editor <cli>', 'editor CLI to use with --open (code, cursor, zed, …)')
115
- .option('--dry-run', 'show what would be created without executing any git commands or writing files')
116
- .option('--json', 'emit JSON on success or error instead of human-readable output')
117
- .action(notImplemented('new'));
110
+ .command("new [branch]")
111
+ .description("create a new branch or detached linked worktree")
112
+ .option("-f, --force", "remove and recreate the worktree if the target path already exists")
113
+ .option("--detached", "create a detached worktree without a branch")
114
+ .option("--open", "open the new worktree in an editor after creation")
115
+ .option("--editor <cli>", "editor CLI to use with --open (code, cursor, zed, …)")
116
+ .option("--dry-run", "show what would be created without executing any git commands or writing files")
117
+ .option("--json", "emit JSON on success or error instead of human-readable output")
118
+ .action(notImplemented("new"));
118
119
  program
119
- .command('init [shell]')
120
- .description('print or install shell integration')
121
- .option('--write', 'write the integration to the shell config file')
122
- .action(notImplemented('init'));
120
+ .command("init [shell]")
121
+ .description("print or install shell integration")
122
+ .option("--write", "write the integration to the shell config file")
123
+ .action(notImplemented("init"));
123
124
  program
124
- .command('completion [shell]')
125
- .description('print shell completion definitions')
126
- .action(notImplemented('completion'));
125
+ .command("completion [shell]")
126
+ .description("print shell completion definitions")
127
+ .action(notImplemented("completion"));
127
128
  program
128
- .command('pr <ref>')
129
- .description('fetch a pull request by number, #number, or URL into a linked worktree')
130
- .option('--dry-run', 'show what would be created without executing any git commands or writing files')
131
- .option('--json', 'emit JSON on success or error instead of human-readable output')
132
- .action(notImplemented('pr'));
129
+ .command("pr <ref>")
130
+ .description("fetch a pull request by number, #number, or URL into a linked worktree")
131
+ .option("--dry-run", "show what would be created without executing any git commands or writing files")
132
+ .option("--json", "emit JSON on success or error instead of human-readable output")
133
+ .action(notImplemented("pr"));
133
134
  program
134
- .command('back [n]')
135
- .description('navigate to the previously visited worktree, optionally N steps back')
136
- .option('--print', 'print the resolved worktree path explicitly')
137
- .action(notImplemented('back'));
135
+ .command("back [n]")
136
+ .description("navigate to the previously visited worktree, optionally N steps back")
137
+ .option("--print", "print the resolved worktree path explicitly")
138
+ .action(notImplemented("back"));
138
139
  program
139
- .command('history')
140
- .description('show navigation history')
141
- .option('--json', 'print history as JSON')
142
- .action(notImplemented('history'));
140
+ .command("history")
141
+ .description("show navigation history")
142
+ .option("--json", "print history as JSON")
143
+ .action(notImplemented("history"));
143
144
  program
144
- .command('open [branch]')
145
- .description('open the worktree in an editor')
146
- .option('--editor <cli>', 'editor CLI to use (code, cursor, zed, windsurf, subl, …)')
147
- .option('--save', 'save the chosen editor to global config')
148
- .option('--workspace', 'generate a .code-workspace file before opening (VS Code / Cursor / Windsurf)')
149
- .action(notImplemented('open'));
145
+ .command("open [branch]")
146
+ .description("open the worktree in an editor")
147
+ .option("--editor <cli>", "editor CLI to use (code, cursor, zed, windsurf, subl, …)")
148
+ .option("--save", "save the chosen editor to global config")
149
+ .option("--workspace", "generate a .code-workspace file before opening (VS Code / Cursor / Windsurf)")
150
+ .action(notImplemented("open"));
150
151
  program
151
- .command('go [branch]')
152
- .alias('jump')
153
- .description('print or select a worktree path')
154
- .option('--print', 'print the resolved worktree path explicitly')
155
- .action(notImplemented('go'));
152
+ .command("go [branch]")
153
+ .alias("jump")
154
+ .description("print or select a worktree path")
155
+ .option("--print", "print the resolved worktree path explicitly")
156
+ .action(notImplemented("go"));
156
157
  program
157
- .command('root')
158
- .description('print the main repository root path')
159
- .option('--print', 'print the resolved repository root path explicitly')
160
- .action(notImplemented('root'));
158
+ .command("root")
159
+ .description("print the main repository root path")
160
+ .option("--print", "print the resolved repository root path explicitly")
161
+ .action(notImplemented("root"));
161
162
  program
162
- .command('status')
163
- .description('summarize repository and worktree health')
164
- .option('--json', 'print repository and worktree health as JSON')
165
- .action(notImplemented('status'));
163
+ .command("status")
164
+ .description("summarize repository and worktree health")
165
+ .option("--json", "print repository and worktree health as JSON")
166
+ .action(notImplemented("status"));
166
167
  program
167
- .command('sync')
168
- .description('fetch and update one or all worktrees')
169
- .option('--all', 'sync every worktree in the repository')
170
- .option('--json', 'emit JSON on success or error instead of human-readable output')
171
- .action(notImplemented('sync'));
168
+ .command("sync")
169
+ .description("fetch and update one or all worktrees")
170
+ .option("--all", "sync every worktree in the repository")
171
+ .option("--json", "emit JSON on success or error instead of human-readable output")
172
+ .action(notImplemented("sync"));
173
+ const syncFilesCommand = program
174
+ .command("sync-files")
175
+ .description("manage local files copied into new worktrees")
176
+ .option("--json", "emit JSON instead of human-readable output")
177
+ .action(notImplemented("sync-files"));
178
+ syncFilesCommand
179
+ .command("list")
180
+ .description("list files synced into new worktrees for this repo")
181
+ .option("--json", "emit JSON instead of human-readable output")
182
+ .action(notImplemented("sync-files list"));
183
+ syncFilesCommand
184
+ .command("add <paths...>")
185
+ .description("add repo-local sync files to global config")
186
+ .option("--json", "emit JSON instead of human-readable output")
187
+ .action(notImplemented("sync-files add"));
188
+ syncFilesCommand
189
+ .command("remove <paths...>")
190
+ .alias("rm")
191
+ .description("remove repo-local sync files from global config")
192
+ .option("--json", "emit JSON instead of human-readable output")
193
+ .action(notImplemented("sync-files remove"));
172
194
  program
173
- .command('ls')
174
- .description('list active worktrees')
175
- .option('--compact', 'show only branch and path columns')
176
- .option('--json', 'print active worktrees as JSON')
177
- .action(notImplemented('ls'));
195
+ .command("ls")
196
+ .description("list active worktrees")
197
+ .option("--compact", "show only branch and path columns")
198
+ .option("--json", "print active worktrees as JSON")
199
+ .action(notImplemented("ls"));
178
200
  program
179
- .command('clean')
180
- .description('interactively prune linked worktrees')
181
- .option('-f, --force', 'bypass prompts, force-remove dirty worktrees, and force-delete unmerged branches')
182
- .option('--stale', 'only target clean worktrees whose upstream is gone and branch is merged into the default branch')
183
- .option('--dry-run', 'show what would be deleted without removing anything')
184
- .option('--json', 'emit JSON on success or error instead of human-readable output')
185
- .action(notImplemented('clean'));
201
+ .command("clean")
202
+ .description("interactively prune linked worktrees")
203
+ .option("-f, --force", "bypass prompts, force-remove dirty worktrees, and force-delete unmerged branches")
204
+ .option("--stale", "only target clean worktrees whose upstream is gone and branch is merged into the default branch")
205
+ .option("--dry-run", "show what would be deleted without removing anything")
206
+ .option("--json", "emit JSON on success or error instead of human-readable output")
207
+ .action(notImplemented("clean"));
186
208
  program
187
- .command('remove [branch]')
188
- .alias('rm')
189
- .description('remove a linked worktree and delete its branch when present')
190
- .option('-f, --force', 'bypass prompts, force-remove a dirty worktree, and force-delete an unmerged branch')
191
- .option('--dry-run', 'show what would be deleted without removing anything')
192
- .option('--json', 'emit JSON on success or error instead of human-readable output')
193
- .action(notImplemented('remove'));
209
+ .command("remove [branch]")
210
+ .alias("rm")
211
+ .description("remove a linked worktree and delete its branch when present")
212
+ .option("-f, --force", "bypass prompts, force-remove a dirty worktree, and force-delete an unmerged branch")
213
+ .option("--dry-run", "show what would be deleted without removing anything")
214
+ .option("--json", "emit JSON on success or error instead of human-readable output")
215
+ .action(notImplemented("remove"));
194
216
  program
195
- .command('trigger-hook <hook>')
196
- .description('run a named hook (afterCreate, afterEnter, beforeRemove) in the current worktree')
197
- .action(notImplemented('trigger-hook'));
217
+ .command("run-hook <hook>")
218
+ .alias("trigger-hook")
219
+ .description("run a named hook (after-create, after-enter, before-remove) in the current worktree")
220
+ .action(notImplemented("run-hook"));
198
221
  program
199
- .command('warp [branch]')
200
- .description('jump to any worktree across all known repos')
201
- .option('-n, --new [branch]', 'create a new worktree in a registered repo')
222
+ .command("warp [branch]")
223
+ .description("jump to any worktree across all known repos")
224
+ .option("-n, --new [branch]", "create a new worktree in a registered repo")
202
225
  // --print is the shell-wrapper bypass signal (see SHELL_WRAPPED_COMMANDS in init.ts).
203
226
  // The shell omits GJI_WARP_OUTPUT_FILE, so writeShellOutput falls through to stdout.
204
- .option('--print', 'print the resolved worktree path without changing directory')
205
- .option('--json', 'emit JSON on success or error instead of human-readable output')
206
- .action(notImplemented('warp'));
227
+ .option("--print", "print the resolved worktree path without changing directory")
228
+ .option("--json", "emit JSON on success or error instead of human-readable output")
229
+ .action(notImplemented("warp"));
207
230
  const configCommand = program
208
- .command('config')
209
- .description('manage global config defaults')
210
- .action(notImplemented('config'));
231
+ .command("config")
232
+ .description("manage global config defaults")
233
+ .action(notImplemented("config"));
211
234
  configCommand
212
- .command('get [key]')
213
- .description('print the global config or a single key')
214
- .action(notImplemented('config get'));
235
+ .command("get [key]")
236
+ .description("print the global config or a single key")
237
+ .action(notImplemented("config get"));
215
238
  configCommand
216
- .command('set <key> <value>')
217
- .description('set a global config value')
218
- .action(notImplemented('config set'));
239
+ .command("set <key> <value>")
240
+ .description("set a global config value")
241
+ .action(notImplemented("config set"));
219
242
  configCommand
220
- .command('unset <key>')
221
- .description('remove a global config value')
222
- .action(notImplemented('config unset'));
243
+ .command("unset <key>")
244
+ .description("remove a global config value")
245
+ .action(notImplemented("config unset"));
223
246
  }
224
247
  function attachCommandActions(program, options) {
225
248
  program.commands
226
- .find((command) => command.name() === 'new')
249
+ .find((command) => command.name() === "new")
227
250
  ?.action(async (branch, commandOptions) => {
228
- const exitCode = await runNewCommand({ ...options, branch, detached: commandOptions.detached, dryRun: commandOptions.dryRun, editor: commandOptions.editor, force: commandOptions.force, json: commandOptions.json, open: commandOptions.open });
251
+ const exitCode = await runNewCommand({
252
+ ...options,
253
+ branch,
254
+ detached: commandOptions.detached,
255
+ dryRun: commandOptions.dryRun,
256
+ editor: commandOptions.editor,
257
+ force: commandOptions.force,
258
+ json: commandOptions.json,
259
+ open: commandOptions.open,
260
+ });
229
261
  if (exitCode !== 0) {
230
262
  throw commanderExit(exitCode);
231
263
  }
232
264
  });
233
265
  program.commands
234
- .find((command) => command.name() === 'init')
266
+ .find((command) => command.name() === "init")
235
267
  ?.action(async (shell, commandOptions) => {
236
268
  const exitCode = await runInitCommand({
237
269
  cwd: options.cwd,
@@ -245,7 +277,7 @@ function attachCommandActions(program, options) {
245
277
  }
246
278
  });
247
279
  program.commands
248
- .find((command) => command.name() === 'completion')
280
+ .find((command) => command.name() === "completion")
249
281
  ?.action(async (shell) => {
250
282
  const exitCode = await runCompletionCommand({
251
283
  shell,
@@ -257,15 +289,22 @@ function attachCommandActions(program, options) {
257
289
  }
258
290
  });
259
291
  program.commands
260
- .find((command) => command.name() === 'pr')
292
+ .find((command) => command.name() === "pr")
261
293
  ?.action(async (number, commandOptions) => {
262
- const exitCode = await runPrCommand({ cwd: options.cwd, dryRun: commandOptions.dryRun, json: commandOptions.json, number, stderr: options.stderr, stdout: options.stdout });
294
+ const exitCode = await runPrCommand({
295
+ cwd: options.cwd,
296
+ dryRun: commandOptions.dryRun,
297
+ json: commandOptions.json,
298
+ number,
299
+ stderr: options.stderr,
300
+ stdout: options.stdout,
301
+ });
263
302
  if (exitCode !== 0) {
264
303
  throw commanderExit(exitCode);
265
304
  }
266
305
  });
267
306
  program.commands
268
- .find((command) => command.name() === 'back')
307
+ .find((command) => command.name() === "back")
269
308
  ?.action(async (n, commandOptions) => {
270
309
  if (n !== undefined && !/^\d+$/.test(n)) {
271
310
  options.stderr(`gji back: invalid step count: ${n}\n`);
@@ -284,7 +323,7 @@ function attachCommandActions(program, options) {
284
323
  }
285
324
  });
286
325
  program.commands
287
- .find((command) => command.name() === 'history')
326
+ .find((command) => command.name() === "history")
288
327
  ?.action(async (commandOptions) => {
289
328
  const exitCode = await runHistoryCommand({
290
329
  cwd: options.cwd,
@@ -296,7 +335,7 @@ function attachCommandActions(program, options) {
296
335
  }
297
336
  });
298
337
  program.commands
299
- .find((command) => command.name() === 'open')
338
+ .find((command) => command.name() === "open")
300
339
  ?.action(async (branch, commandOptions) => {
301
340
  const exitCode = await runOpenCommand({
302
341
  branch,
@@ -312,7 +351,7 @@ function attachCommandActions(program, options) {
312
351
  }
313
352
  });
314
353
  program.commands
315
- .find((command) => command.name() === 'go')
354
+ .find((command) => command.name() === "go")
316
355
  ?.action(async (branch, commandOptions) => {
317
356
  const exitCode = await runGoCommand({
318
357
  branch,
@@ -326,7 +365,7 @@ function attachCommandActions(program, options) {
326
365
  }
327
366
  });
328
367
  program.commands
329
- .find((command) => command.name() === 'root')
368
+ .find((command) => command.name() === "root")
330
369
  ?.action(async (commandOptions) => {
331
370
  const exitCode = await runRootCommand({
332
371
  cwd: options.cwd,
@@ -338,7 +377,7 @@ function attachCommandActions(program, options) {
338
377
  }
339
378
  });
340
379
  program.commands
341
- .find((command) => command.name() === 'status')
380
+ .find((command) => command.name() === "status")
342
381
  ?.action(async (commandOptions) => {
343
382
  const exitCode = await runStatusCommand({
344
383
  cwd: options.cwd,
@@ -350,7 +389,7 @@ function attachCommandActions(program, options) {
350
389
  }
351
390
  });
352
391
  program.commands
353
- .find((command) => command.name() === 'sync')
392
+ .find((command) => command.name() === "sync")
354
393
  ?.action(async (commandOptions) => {
355
394
  const exitCode = await runSyncCommand({
356
395
  all: commandOptions.all,
@@ -363,8 +402,66 @@ function attachCommandActions(program, options) {
363
402
  throw commanderExit(exitCode);
364
403
  }
365
404
  });
405
+ const syncFilesCommand = program.commands.find((command) => command.name() === "sync-files");
406
+ syncFilesCommand?.action(async (commandOptions) => {
407
+ const exitCode = await runSyncFilesCommand({
408
+ action: "list",
409
+ cwd: options.cwd,
410
+ json: commandOptions.json,
411
+ stderr: options.stderr,
412
+ stdout: options.stdout,
413
+ });
414
+ if (exitCode !== 0) {
415
+ throw commanderExit(exitCode);
416
+ }
417
+ });
418
+ syncFilesCommand?.commands
419
+ .find((command) => command.name() === "list")
420
+ ?.action(async (commandOptions) => {
421
+ const exitCode = await runSyncFilesCommand({
422
+ action: "list",
423
+ cwd: options.cwd,
424
+ json: commandOptions.json || syncFilesCommand?.opts().json,
425
+ stderr: options.stderr,
426
+ stdout: options.stdout,
427
+ });
428
+ if (exitCode !== 0) {
429
+ throw commanderExit(exitCode);
430
+ }
431
+ });
432
+ syncFilesCommand?.commands
433
+ .find((command) => command.name() === "add")
434
+ ?.action(async (paths, commandOptions) => {
435
+ const exitCode = await runSyncFilesCommand({
436
+ action: "add",
437
+ cwd: options.cwd,
438
+ json: commandOptions.json || syncFilesCommand?.opts().json,
439
+ paths,
440
+ stderr: options.stderr,
441
+ stdout: options.stdout,
442
+ });
443
+ if (exitCode !== 0) {
444
+ throw commanderExit(exitCode);
445
+ }
446
+ });
447
+ const runSyncFilesRemoveCommand = async (paths, commandOptions) => {
448
+ const exitCode = await runSyncFilesCommand({
449
+ action: "remove",
450
+ cwd: options.cwd,
451
+ json: commandOptions.json || syncFilesCommand?.opts().json,
452
+ paths,
453
+ stderr: options.stderr,
454
+ stdout: options.stdout,
455
+ });
456
+ if (exitCode !== 0) {
457
+ throw commanderExit(exitCode);
458
+ }
459
+ };
460
+ syncFilesCommand?.commands
461
+ .find((command) => command.name() === "remove")
462
+ ?.action(runSyncFilesRemoveCommand);
366
463
  program.commands
367
- .find((command) => command.name() === 'ls')
464
+ .find((command) => command.name() === "ls")
368
465
  ?.action(async (commandOptions) => {
369
466
  const exitCode = await runLsCommand({
370
467
  compact: commandOptions.compact,
@@ -377,7 +474,7 @@ function attachCommandActions(program, options) {
377
474
  }
378
475
  });
379
476
  program.commands
380
- .find((command) => command.name() === 'clean')
477
+ .find((command) => command.name() === "clean")
381
478
  ?.action(async (commandOptions) => {
382
479
  const exitCode = await runCleanCommand({
383
480
  cwd: options.cwd,
@@ -407,12 +504,12 @@ function attachCommandActions(program, options) {
407
504
  }
408
505
  };
409
506
  program.commands
410
- .find((command) => command.name() === 'remove')
507
+ .find((command) => command.name() === "remove")
411
508
  ?.action(runRemovalCommand);
412
509
  program.commands
413
- .find((command) => command.name() === 'trigger-hook')
510
+ .find((command) => command.name() === "run-hook")
414
511
  ?.action(async (hook) => {
415
- const exitCode = await runTriggerHookCommand({
512
+ const exitCode = await runHookCommand({
416
513
  cwd: options.cwd,
417
514
  hook,
418
515
  stderr: options.stderr,
@@ -422,11 +519,11 @@ function attachCommandActions(program, options) {
422
519
  }
423
520
  });
424
521
  program.commands
425
- .find((command) => command.name() === 'warp')
522
+ .find((command) => command.name() === "warp")
426
523
  ?.action(async (branch, commandOptions) => {
427
524
  const newFlag = commandOptions.new;
428
525
  const newWorktree = newFlag !== undefined && newFlag !== false;
429
- const newBranch = typeof newFlag === 'string' ? newFlag : undefined;
526
+ const newBranch = typeof newFlag === "string" ? newFlag : undefined;
430
527
  const exitCode = await runWarpCommand({
431
528
  branch: newWorktree ? (newBranch ?? branch) : branch,
432
529
  cwd: options.cwd,
@@ -439,7 +536,7 @@ function attachCommandActions(program, options) {
439
536
  throw commanderExit(exitCode);
440
537
  }
441
538
  });
442
- const configCommand = program.commands.find((command) => command.name() === 'config');
539
+ const configCommand = program.commands.find((command) => command.name() === "config");
443
540
  configCommand?.action(async () => {
444
541
  const exitCode = await runConfigCommand({
445
542
  cwd: options.cwd,
@@ -449,9 +546,11 @@ function attachCommandActions(program, options) {
449
546
  throw commanderExit(exitCode);
450
547
  }
451
548
  });
452
- configCommand?.commands.find((command) => command.name() === 'get')?.action(async (key) => {
549
+ configCommand?.commands
550
+ .find((command) => command.name() === "get")
551
+ ?.action(async (key) => {
453
552
  const exitCode = await runConfigCommand({
454
- action: 'get',
553
+ action: "get",
455
554
  cwd: options.cwd,
456
555
  key,
457
556
  stdout: options.stdout,
@@ -461,10 +560,10 @@ function attachCommandActions(program, options) {
461
560
  }
462
561
  });
463
562
  configCommand?.commands
464
- .find((command) => command.name() === 'set')
563
+ .find((command) => command.name() === "set")
465
564
  ?.action(async (key, value) => {
466
565
  const exitCode = await runConfigCommand({
467
- action: 'set',
566
+ action: "set",
468
567
  cwd: options.cwd,
469
568
  key,
470
569
  stdout: options.stdout,
@@ -474,9 +573,11 @@ function attachCommandActions(program, options) {
474
573
  throw commanderExit(exitCode);
475
574
  }
476
575
  });
477
- configCommand?.commands.find((command) => command.name() === 'unset')?.action(async (key) => {
576
+ configCommand?.commands
577
+ .find((command) => command.name() === "unset")
578
+ ?.action(async (key) => {
478
579
  const exitCode = await runConfigCommand({
479
- action: 'unset',
580
+ action: "unset",
480
581
  cwd: options.cwd,
481
582
  key,
482
583
  stdout: options.stdout,
@@ -493,14 +594,14 @@ function notImplemented(commandName) {
493
594
  }
494
595
  function commanderExit(exitCode) {
495
596
  const error = new Error(`Command exited with code ${exitCode}.`);
496
- error.code = 'commander.executeSubCommandAsync';
597
+ error.code = "commander.executeSubCommandAsync";
497
598
  error.exitCode = exitCode;
498
599
  return error;
499
600
  }
500
601
  function isCommanderExit(error) {
501
602
  return (error instanceof Error &&
502
- 'code' in error &&
503
- 'exitCode' in error &&
504
- typeof error.code === 'string' &&
505
- typeof error.exitCode === 'number');
603
+ "code" in error &&
604
+ "exitCode" in error &&
605
+ typeof error.code === "string" &&
606
+ typeof error.exitCode === "number");
506
607
  }