ace-git-worktree 0.19.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.
- checksums.yaml +7 -0
- data/.ace-defaults/git/worktree.yml +250 -0
- data/.ace-defaults/nav/protocols/wfi-sources/ace-git-worktree.yml +19 -0
- data/CHANGELOG.md +957 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/Rakefile +14 -0
- data/docs/demo/ace-git-worktree-getting-started.gif +0 -0
- data/docs/demo/ace-git-worktree-getting-started.tape.yml +28 -0
- data/docs/demo/fixtures/README.md +3 -0
- data/docs/demo/fixtures/sample.txt +1 -0
- data/docs/getting-started.md +114 -0
- data/docs/handbook.md +38 -0
- data/docs/usage.md +334 -0
- data/exe/ace-git-worktree +24 -0
- data/handbook/agents/worktree.ag.md +189 -0
- data/handbook/skills/as-git-worktree/SKILL.md +27 -0
- data/handbook/skills/as-git-worktree-create/SKILL.md +21 -0
- data/handbook/skills/as-git-worktree-manage/SKILL.md +20 -0
- data/handbook/workflow-instructions/git/worktree-create.wf.md +262 -0
- data/handbook/workflow-instructions/git/worktree-manage.wf.md +384 -0
- data/handbook/workflow-instructions/git/worktree.wf.md +224 -0
- data/lib/ace/git/worktree/atoms/git_command.rb +121 -0
- data/lib/ace/git/worktree/atoms/path_expander.rb +189 -0
- data/lib/ace/git/worktree/atoms/slug_generator.rb +235 -0
- data/lib/ace/git/worktree/atoms/task_id_extractor.rb +91 -0
- data/lib/ace/git/worktree/cli/commands/config.rb +50 -0
- data/lib/ace/git/worktree/cli/commands/create.rb +80 -0
- data/lib/ace/git/worktree/cli/commands/list.rb +76 -0
- data/lib/ace/git/worktree/cli/commands/prune.rb +43 -0
- data/lib/ace/git/worktree/cli/commands/remove.rb +48 -0
- data/lib/ace/git/worktree/cli/commands/shared_helpers.rb +66 -0
- data/lib/ace/git/worktree/cli/commands/switch.rb +44 -0
- data/lib/ace/git/worktree/cli.rb +103 -0
- data/lib/ace/git/worktree/commands/config_command.rb +351 -0
- data/lib/ace/git/worktree/commands/create_command.rb +961 -0
- data/lib/ace/git/worktree/commands/list_command.rb +247 -0
- data/lib/ace/git/worktree/commands/prune_command.rb +260 -0
- data/lib/ace/git/worktree/commands/remove_command.rb +522 -0
- data/lib/ace/git/worktree/commands/switch_command.rb +249 -0
- data/lib/ace/git/worktree/configuration.rb +167 -0
- data/lib/ace/git/worktree/models/worktree_config.rb +502 -0
- data/lib/ace/git/worktree/models/worktree_info.rb +303 -0
- data/lib/ace/git/worktree/models/worktree_metadata.rb +294 -0
- data/lib/ace/git/worktree/molecules/config_loader.rb +125 -0
- data/lib/ace/git/worktree/molecules/current_task_linker.rb +136 -0
- data/lib/ace/git/worktree/molecules/hook_executor.rb +361 -0
- data/lib/ace/git/worktree/molecules/parent_task_resolver.rb +186 -0
- data/lib/ace/git/worktree/molecules/pr_creator.rb +253 -0
- data/lib/ace/git/worktree/molecules/task_committer.rb +329 -0
- data/lib/ace/git/worktree/molecules/task_fetcher.rb +244 -0
- data/lib/ace/git/worktree/molecules/task_pusher.rb +183 -0
- data/lib/ace/git/worktree/molecules/task_status_updater.rb +447 -0
- data/lib/ace/git/worktree/molecules/worktree_creator.rb +832 -0
- data/lib/ace/git/worktree/molecules/worktree_lister.rb +337 -0
- data/lib/ace/git/worktree/molecules/worktree_remover.rb +416 -0
- data/lib/ace/git/worktree/organisms/task_worktree_orchestrator.rb +906 -0
- data/lib/ace/git/worktree/organisms/worktree_manager.rb +714 -0
- data/lib/ace/git/worktree/version.rb +9 -0
- data/lib/ace/git/worktree.rb +215 -0
- metadata +218 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require_relative "shared_helpers"
|
|
5
|
+
require_relative "../../commands/list_command"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Git
|
|
9
|
+
module Worktree
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
class List < Ace::Support::Cli::Command
|
|
13
|
+
include SharedHelpers
|
|
14
|
+
|
|
15
|
+
desc "List all worktrees with optional filtering"
|
|
16
|
+
|
|
17
|
+
example [
|
|
18
|
+
" # List all worktrees",
|
|
19
|
+
"--show-tasks # Include task associations",
|
|
20
|
+
"--format json # JSON output",
|
|
21
|
+
"--search auth # Filter by branch pattern"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
option :format, desc: "Output format: table, json, simple", aliases: [], default: "table"
|
|
25
|
+
option :show_tasks, desc: "Include task associations", type: :boolean, aliases: ["--show-tasks"]
|
|
26
|
+
option :task_associated, desc: "Show only task-associated worktrees", type: :boolean, aliases: ["--task-associated"]
|
|
27
|
+
option :usable, desc: "Show only usable worktrees", type: :boolean, aliases: ["--usable"]
|
|
28
|
+
option :search, desc: "Filter by branch name pattern", aliases: []
|
|
29
|
+
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
30
|
+
option :verbose, type: :boolean, aliases: ["-v"], desc: "Show verbose output"
|
|
31
|
+
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
32
|
+
|
|
33
|
+
def call(**options)
|
|
34
|
+
display_config_summary("list", options) unless options[:format] == "json"
|
|
35
|
+
|
|
36
|
+
# Keep explicit false values as --no-* flags so legacy parser receives filters.
|
|
37
|
+
args = list_options_to_args(options)
|
|
38
|
+
|
|
39
|
+
Ace::Git::Worktree::Commands::ListCommand.new.run(args)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def list_options_to_args(options)
|
|
45
|
+
args = []
|
|
46
|
+
args.concat(format_arg(options))
|
|
47
|
+
args << "--show-tasks" if options[:show_tasks]
|
|
48
|
+
|
|
49
|
+
unless options[:task_associated].nil?
|
|
50
|
+
args << (options[:task_associated] ? "--task-associated" : "--no-task-associated")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
unless options[:usable].nil?
|
|
54
|
+
args << (options[:usable] ? "--usable" : "--no-usable")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if options[:search].is_a?(String) && !options[:search].empty?
|
|
58
|
+
args << "--search"
|
|
59
|
+
args << options[:search]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
args
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def format_arg(options)
|
|
66
|
+
format = options[:format]
|
|
67
|
+
return [] if format.nil? || format.empty?
|
|
68
|
+
|
|
69
|
+
["--format", format]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require_relative "shared_helpers"
|
|
5
|
+
require_relative "../../commands/prune_command"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Git
|
|
9
|
+
module Worktree
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
class Prune < Ace::Support::Cli::Command
|
|
13
|
+
include SharedHelpers
|
|
14
|
+
|
|
15
|
+
desc "Clean up deleted worktrees from git metadata"
|
|
16
|
+
|
|
17
|
+
example [
|
|
18
|
+
" # Prune deleted worktrees",
|
|
19
|
+
"--dry-run # Preview what would be pruned",
|
|
20
|
+
"--cleanup-directories # Also remove orphaned directories"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
option :dry_run, desc: "Show what would be pruned", type: :boolean, aliases: ["--dry-run"]
|
|
24
|
+
option :cleanup_directories, desc: "Remove orphaned worktree directories", type: :boolean, aliases: ["--cleanup-directories"]
|
|
25
|
+
option :force, desc: "Force cleanup", type: :boolean, aliases: []
|
|
26
|
+
option :verbose, desc: "Show verbose output", type: :boolean, aliases: ["-v"]
|
|
27
|
+
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
28
|
+
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
29
|
+
|
|
30
|
+
def call(**options)
|
|
31
|
+
display_config_summary("prune", options)
|
|
32
|
+
|
|
33
|
+
# Convert ace-support-cli options to args array format
|
|
34
|
+
args = options_to_args(options)
|
|
35
|
+
|
|
36
|
+
Ace::Git::Worktree::Commands::PruneCommand.new.run(args)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require_relative "shared_helpers"
|
|
5
|
+
require_relative "../../commands/remove_command"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Git
|
|
9
|
+
module Worktree
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
class Remove < Ace::Support::Cli::Command
|
|
13
|
+
include SharedHelpers
|
|
14
|
+
|
|
15
|
+
desc "Remove a git worktree with safety checks"
|
|
16
|
+
|
|
17
|
+
example [
|
|
18
|
+
"--task 081 # Remove task worktree",
|
|
19
|
+
"feature-branch # Remove by branch name",
|
|
20
|
+
"--task 081 --force # Force removal with changes"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
argument :identifier, required: false, desc: "Worktree identifier (task ID, branch, directory, or path)"
|
|
24
|
+
|
|
25
|
+
option :task, desc: "Remove worktree for specific task", aliases: []
|
|
26
|
+
option :force, desc: "Force removal even with uncommitted changes", type: :boolean, aliases: []
|
|
27
|
+
option :keep_directory, desc: "Keep the worktree directory", type: :boolean, aliases: ["--keep-directory"]
|
|
28
|
+
option :delete_branch, desc: "Also delete the associated branch", type: :boolean, aliases: ["-D"]
|
|
29
|
+
option :dry_run, desc: "Show what would be removed", type: :boolean, aliases: ["--dry-run"]
|
|
30
|
+
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
31
|
+
option :verbose, type: :boolean, aliases: ["-v"], desc: "Show verbose output"
|
|
32
|
+
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
33
|
+
|
|
34
|
+
def call(identifier: nil, **options)
|
|
35
|
+
display_config_summary("remove", options)
|
|
36
|
+
|
|
37
|
+
# Convert ace-support-cli options to args array format
|
|
38
|
+
args = options_to_args(options)
|
|
39
|
+
args << identifier if identifier
|
|
40
|
+
|
|
41
|
+
Ace::Git::Worktree::Commands::RemoveCommand.new.run(args)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/core"
|
|
4
|
+
|
|
5
|
+
module Ace
|
|
6
|
+
module Git
|
|
7
|
+
module Worktree
|
|
8
|
+
module CLI
|
|
9
|
+
module Commands
|
|
10
|
+
# Shared helper methods for CLI commands
|
|
11
|
+
#
|
|
12
|
+
# Include this module in CLI command classes to avoid code duplication
|
|
13
|
+
# of common patterns like config summary display and options conversion.
|
|
14
|
+
module SharedHelpers
|
|
15
|
+
include Ace::Support::Cli::Base
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
# Display config summary unless quiet mode is enabled
|
|
20
|
+
#
|
|
21
|
+
# @param command [String] Command name for display
|
|
22
|
+
# @param options [Hash] CLI options hash
|
|
23
|
+
def display_config_summary(command, options)
|
|
24
|
+
return if quiet?(options)
|
|
25
|
+
|
|
26
|
+
Ace::Core::Atoms::ConfigSummary.display(
|
|
27
|
+
command: command,
|
|
28
|
+
config: Ace::Git::Worktree.config,
|
|
29
|
+
defaults: {},
|
|
30
|
+
options: options
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Convert ace-support-cli options hash to args array format for legacy commands
|
|
35
|
+
#
|
|
36
|
+
# @param options [Hash] CLI options hash
|
|
37
|
+
# @return [Array<String>] Arguments array
|
|
38
|
+
#
|
|
39
|
+
# @note Boolean false values are skipped (not converted to --no-flag).
|
|
40
|
+
# This means there's no distinction between "not specified" and "explicitly
|
|
41
|
+
# set to false". If a command needs to distinguish these cases, it should
|
|
42
|
+
# handle the option directly rather than using this converter.
|
|
43
|
+
def options_to_args(options)
|
|
44
|
+
args = []
|
|
45
|
+
options.each do |key, value|
|
|
46
|
+
next if value.nil? || %i[quiet verbose debug].include?(key)
|
|
47
|
+
|
|
48
|
+
arg_key = key.to_s.tr("_", "-")
|
|
49
|
+
if value == true
|
|
50
|
+
args << "--#{arg_key}"
|
|
51
|
+
elsif value == false
|
|
52
|
+
# Skip boolean false options - no distinction between unset and false
|
|
53
|
+
next
|
|
54
|
+
elsif value.is_a?(String)
|
|
55
|
+
args << "--#{arg_key}"
|
|
56
|
+
args << value
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
args
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require_relative "shared_helpers"
|
|
5
|
+
require_relative "../../commands/switch_command"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Git
|
|
9
|
+
module Worktree
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
class Switch < Ace::Support::Cli::Command
|
|
13
|
+
include SharedHelpers
|
|
14
|
+
|
|
15
|
+
desc "Switch to a worktree by returning its path"
|
|
16
|
+
|
|
17
|
+
example [
|
|
18
|
+
"081 # Switch by task ID",
|
|
19
|
+
"feature-branch # Switch by branch name",
|
|
20
|
+
"--list # List available worktrees"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
argument :identifier, required: false, desc: "Worktree identifier (task ID, branch, directory, or path)"
|
|
24
|
+
|
|
25
|
+
option :list, desc: "List available worktrees", type: :boolean, aliases: ["-l"]
|
|
26
|
+
option :verbose, desc: "Show verbose output", type: :boolean, aliases: ["-v"]
|
|
27
|
+
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
28
|
+
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
29
|
+
|
|
30
|
+
def call(identifier: nil, **options)
|
|
31
|
+
display_config_summary("switch", options)
|
|
32
|
+
|
|
33
|
+
# Convert ace-support-cli options to args array format
|
|
34
|
+
args = options_to_args(options)
|
|
35
|
+
args << identifier if identifier
|
|
36
|
+
|
|
37
|
+
Ace::Git::Worktree::Commands::SwitchCommand.new.run(args)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
|
|
5
|
+
require_relative "version"
|
|
6
|
+
require_relative "cli/commands/create"
|
|
7
|
+
require_relative "cli/commands/list"
|
|
8
|
+
require_relative "cli/commands/switch"
|
|
9
|
+
require_relative "cli/commands/remove"
|
|
10
|
+
require_relative "cli/commands/prune"
|
|
11
|
+
require_relative "cli/commands/config"
|
|
12
|
+
require "ace/core"
|
|
13
|
+
require "ace/support/cli"
|
|
14
|
+
|
|
15
|
+
module Ace
|
|
16
|
+
module Git
|
|
17
|
+
module Worktree
|
|
18
|
+
# ace-support-cli based CLI registry for ace-git-worktree
|
|
19
|
+
#
|
|
20
|
+
# This follows the Hanami pattern with all commands in CLI::Commands:: namespace.
|
|
21
|
+
module CLI
|
|
22
|
+
extend Ace::Support::Cli::RegistryDsl
|
|
23
|
+
|
|
24
|
+
PROGRAM_NAME = "ace-git-worktree"
|
|
25
|
+
|
|
26
|
+
REGISTERED_COMMANDS = [
|
|
27
|
+
["create", "Create a new worktree for task, PR, or branch"],
|
|
28
|
+
["list", "List active worktrees with optional task metadata"],
|
|
29
|
+
["switch", "Resolve a worktree path for cd navigation"],
|
|
30
|
+
["remove", "Remove a worktree by task, branch, or path"],
|
|
31
|
+
["prune", "Prune stale/deleted worktree references"],
|
|
32
|
+
["config", "Show and validate configuration"]
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
HELP_EXAMPLES = [
|
|
36
|
+
"ace-git-worktree create --task 148 # Isolated worktree for task",
|
|
37
|
+
"ace-git-worktree list --show-tasks # Worktrees with task context",
|
|
38
|
+
"ace-git-worktree switch 148 # Get path for cd",
|
|
39
|
+
"ace-git-worktree prune --dry-run # Preview stale cleanup"
|
|
40
|
+
].freeze
|
|
41
|
+
|
|
42
|
+
# Captured command exit code from last run.
|
|
43
|
+
@captured_exit_code = nil
|
|
44
|
+
|
|
45
|
+
# Start the CLI.
|
|
46
|
+
#
|
|
47
|
+
# @param args [Array<String>] Command-line arguments
|
|
48
|
+
# @return [Integer] Exit code (0 for success, non-zero for failure)
|
|
49
|
+
def self.start(args)
|
|
50
|
+
@captured_exit_code = nil
|
|
51
|
+
Ace::Support::Cli::Runner.new(self).call(args: args)
|
|
52
|
+
@captured_exit_code || 0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Wrap a command to capture its exit code.
|
|
56
|
+
#
|
|
57
|
+
# @param command_class [Class] The command class to wrap
|
|
58
|
+
# @return [Class] Wrapped command class
|
|
59
|
+
def self.wrap_command(command_class)
|
|
60
|
+
wrapped = Class.new(Ace::Support::Cli::Command) do
|
|
61
|
+
define_method(:call) do |**kwargs|
|
|
62
|
+
result = command_class.new.call(**kwargs)
|
|
63
|
+
Ace::Git::Worktree::CLI.instance_variable_set(:@captured_exit_code, result) if result.is_a?(Integer)
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
command_class.instance_variables.each do |ivar|
|
|
69
|
+
wrapped.instance_variable_set(ivar, command_class.instance_variable_get(ivar))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
wrapped
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Register commands (Hanami pattern: CLI::Commands::*)
|
|
76
|
+
register "create", wrap_command(CLI::Commands::Create), aliases: []
|
|
77
|
+
register "list", wrap_command(CLI::Commands::List), aliases: ["ls"]
|
|
78
|
+
register "switch", wrap_command(CLI::Commands::Switch), aliases: ["cd"]
|
|
79
|
+
register "remove", wrap_command(CLI::Commands::Remove), aliases: ["rm"]
|
|
80
|
+
register "prune", wrap_command(CLI::Commands::Prune), aliases: []
|
|
81
|
+
register "config", wrap_command(CLI::Commands::Config), aliases: []
|
|
82
|
+
|
|
83
|
+
# Version command
|
|
84
|
+
version_cmd = Ace::Support::Cli::VersionCommand.build(
|
|
85
|
+
gem_name: "ace-git-worktree",
|
|
86
|
+
version: Ace::Git::Worktree::VERSION
|
|
87
|
+
)
|
|
88
|
+
register "version", version_cmd
|
|
89
|
+
register "--version", version_cmd
|
|
90
|
+
|
|
91
|
+
help_cmd = Ace::Support::Cli::HelpCommand.build(
|
|
92
|
+
program_name: PROGRAM_NAME,
|
|
93
|
+
version: Ace::Git::Worktree::VERSION,
|
|
94
|
+
commands: REGISTERED_COMMANDS,
|
|
95
|
+
examples: HELP_EXAMPLES
|
|
96
|
+
)
|
|
97
|
+
register "help", help_cmd
|
|
98
|
+
register "--help", help_cmd
|
|
99
|
+
register "-h", help_cmd
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|