ace-git-worktree 0.21.8 → 0.22.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/docs/usage.md +37 -3
- data/handbook/skills/as-git-worktree-cleanup/SKILL.md +20 -0
- data/handbook/workflow-instructions/git/worktree-cleanup.wf.md +63 -0
- data/handbook/workflow-instructions/git/worktree-create.wf.md +6 -0
- data/lib/ace/git/worktree/cli/commands/bootstrap.rb +43 -0
- data/lib/ace/git/worktree/cli/commands/cleanup.rb +45 -0
- data/lib/ace/git/worktree/cli/commands/config.rb +27 -4
- data/lib/ace/git/worktree/cli/commands/create.rb +1 -0
- data/lib/ace/git/worktree/cli.rb +6 -0
- data/lib/ace/git/worktree/commands/bootstrap_command.rb +159 -0
- data/lib/ace/git/worktree/commands/cleanup_command.rb +307 -0
- data/lib/ace/git/worktree/commands/config_command.rb +354 -181
- data/lib/ace/git/worktree/commands/create_command.rb +5 -0
- data/lib/ace/git/worktree/models/worktree_config.rb +33 -3
- data/lib/ace/git/worktree/molecules/bootstrap_executor.rb +99 -0
- data/lib/ace/git/worktree/molecules/cleanup_applier.rb +225 -0
- data/lib/ace/git/worktree/molecules/cleanup_pr_resolver.rb +213 -0
- data/lib/ace/git/worktree/molecules/cleanup_reporter.rb +396 -0
- data/lib/ace/git/worktree/molecules/config_loader.rb +1 -1
- data/lib/ace/git/worktree/molecules/task_committer.rb +55 -8
- data/lib/ace/git/worktree/molecules/toolchain_truster.rb +112 -0
- data/lib/ace/git/worktree/molecules/worktree_lister.rb +17 -1
- data/lib/ace/git/worktree/organisms/task_worktree_orchestrator.rb +159 -10
- data/lib/ace/git/worktree/organisms/worktree_manager.rb +4 -2
- data/lib/ace/git/worktree/version.rb +1 -1
- metadata +17 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e7afdc95769c4eaebe1974a49534a00e548a17f2519075c10738bd93ad68de5
|
|
4
|
+
data.tar.gz: 43294a3bb9d7bc38da9938f50e8e621ce7a432f54a39ecebbe57a752d46f56d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: af41391d20f9555ddd1da0e6347823c4810dc2d330b38137317e5fc79f7ab1c81a17b43e54d33b666f5cc40163f1a6ea8abca031b94f508bdd4c525a1788a07c
|
|
7
|
+
data.tar.gz: 073f8bdaf60175babf66dfca52880d1ffaab445c92b4c264165cd7792d7e5c8bb5a6be4adcf1e42f7f561b0b7ae019d43ce7ffe0eda0d3032d4377bc14be661e
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.22.0] - 2026-08-13
|
|
11
|
+
### Added
|
|
12
|
+
- Add cleanup plan application with drift guards
|
|
13
|
+
- Classify merged refs with GitHub PR evidence
|
|
14
|
+
- Report repository inventory with ancestry proof
|
|
15
|
+
- Run recoverable preparation phases in place
|
|
16
|
+
- Add bootstrap config management and provenance
|
|
17
|
+
- Fail closed on tracked mise trust verification
|
|
18
|
+
### Fixed
|
|
19
|
+
- Resolve PR 316 findings and finalize cleanup proofs
|
|
20
|
+
- Restrict bookkeeping commits to owned paths
|
|
21
|
+
|
|
10
22
|
## [0.21.8] - 2026-08-12
|
|
11
23
|
|
|
12
24
|
### Technical
|
data/docs/usage.md
CHANGED
|
@@ -19,14 +19,16 @@ gem install ace-git-worktree
|
|
|
19
19
|
|
|
20
20
|
## Command Overview
|
|
21
21
|
|
|
22
|
-
`ace-git-worktree` ships
|
|
22
|
+
`ace-git-worktree` ships seven commands:
|
|
23
23
|
|
|
24
24
|
* `create` for task-aware, PR-aware, and branch-based worktree creation
|
|
25
|
+
* `bootstrap` for rerunning preparation phases (toolchain trust and bootstrap policy) on existing worktrees
|
|
25
26
|
* `list` for active worktree inventory and filtering
|
|
26
27
|
* `switch` for resolving a worktree path you can `cd` into
|
|
28
|
+
* `cleanup` for report/apply cleanup of squash-merged branches
|
|
27
29
|
* `remove` for safe worktree removal
|
|
28
30
|
* `prune` for stale-reference cleanup
|
|
29
|
-
* `config` for configuration inspection and validation
|
|
31
|
+
* `config` for configuration initialization, bootstrap policy settings, inspection, and validation
|
|
30
32
|
|
|
31
33
|
Run `ace-git-worktree --help` for the top-level summary and examples.
|
|
32
34
|
|
|
@@ -112,7 +114,23 @@ Would remove task.081
|
|
|
112
114
|
|
|
113
115
|
**Next steps:** Re-run either command without `--dry-run` once the preview looks correct.
|
|
114
116
|
|
|
115
|
-
### Scenario
|
|
117
|
+
### Scenario 2: Clean up merged worktrees
|
|
118
|
+
|
|
119
|
+
**Goal:** Remove worktrees and branches that have been merged to main.
|
|
120
|
+
|
|
121
|
+
**Commands:**
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Generate a cleanup plan and review it
|
|
125
|
+
ace-git-worktree cleanup --target main
|
|
126
|
+
|
|
127
|
+
# Apply the reviewed plan using the digest from the report
|
|
128
|
+
ace-git-worktree cleanup --target main --apply --approved-digest <sha256-digest>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Outcome:** Merged worktrees, local branches, and remote-tracking branches are removed safely without dropping unmerged work.
|
|
132
|
+
|
|
133
|
+
### Scenario 3: Switch Task Context and Validate Dependencies
|
|
116
134
|
|
|
117
135
|
**Goal:** Show task-associated worktrees separately from non-task worktrees.
|
|
118
136
|
|
|
@@ -277,6 +295,22 @@ ace-git-worktree prune --cleanup-directories
|
|
|
277
295
|
* `-v`, `--verbose` - Show verbose output
|
|
278
296
|
* `-d`, `--debug` - Show debug output
|
|
279
297
|
|
|
298
|
+
### `ace-git-worktree bootstrap [IDENTIFIER]`
|
|
299
|
+
|
|
300
|
+
Rerun preparation phases (toolchain trust and bootstrap policy) for an existing worktree in place.
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
ace-git-worktree bootstrap 081
|
|
304
|
+
ace-git-worktree bootstrap t.081 --json
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Options:**
|
|
308
|
+
|
|
309
|
+
* `--json` - Output format as JSON
|
|
310
|
+
* `-q`, `--quiet` - Suppress non-essential output
|
|
311
|
+
* `-v`, `--verbose` - Show verbose output
|
|
312
|
+
* `-d`, `--debug` - Show debug output
|
|
313
|
+
|
|
280
314
|
### `ace-git-worktree config [SUBCOMMAND]`
|
|
281
315
|
|
|
282
316
|
Show current configuration, validate it, or list the config files in play.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: as-git-worktree-cleanup
|
|
3
|
+
description: Safely inventory and apply cleanup plans for squash-merged worktrees and refs
|
|
4
|
+
# bundle: wfi://git/worktree-cleanup
|
|
5
|
+
# agent: Bash
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools:
|
|
8
|
+
- Bash(ace-git-worktree:*)
|
|
9
|
+
- Bash(ace-bundle:*)
|
|
10
|
+
- Read
|
|
11
|
+
argument-hint: [--target main]
|
|
12
|
+
last_modified: 2026-08-13
|
|
13
|
+
source: ace-git-worktree
|
|
14
|
+
skill:
|
|
15
|
+
kind: workflow
|
|
16
|
+
execution:
|
|
17
|
+
workflow: wfi://git/worktree-cleanup
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Load and run `ace-bundle wfi://git/worktree-cleanup` in the current project, then follow the loaded workflow as the source of truth and execute it end-to-end instead of only summarizing it.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Worktree Cleanup
|
|
3
|
+
description: Safely inventory and apply cleanup plans for squash-merged worktrees and refs
|
|
4
|
+
category: Git
|
|
5
|
+
tags: [git, worktree, cleanup, safely, squash-merge]
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Worktree Cleanup
|
|
10
|
+
|
|
11
|
+
The `ace-git-worktree cleanup` command safely removes stale worktrees, local branches, and remote-tracking branches that have been merged (including squash merges). It uses a two-phase report/apply model with strict ancestry and drift guards.
|
|
12
|
+
|
|
13
|
+
## Generate Cleanup Report
|
|
14
|
+
|
|
15
|
+
First, generate a deterministic, no-mutation inventory of everything that could be cleaned up relative to a target branch:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
ace-git-worktree cleanup --target main --remote origin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This will:
|
|
22
|
+
1. Refresh remote evidence (unless `--offline` is passed).
|
|
23
|
+
2. Find all worktrees, local refs, and remote refs.
|
|
24
|
+
3. Classify each using GitHub PR evidence (exact merge, stable patch equivalence) or Git ancestry.
|
|
25
|
+
4. Output an ordered plan with a **Plan Digest**.
|
|
26
|
+
|
|
27
|
+
### Report Output Interpretation
|
|
28
|
+
|
|
29
|
+
- `✓` (Retain): Item is protected (e.g., primary checkout, dirty worktree) or its ancestry/merge status is unproven.
|
|
30
|
+
- `✗` (Remove): Item is safe to delete because it is fully merged into the target.
|
|
31
|
+
|
|
32
|
+
## Apply Cleanup Plan
|
|
33
|
+
|
|
34
|
+
To execute the deletions, you must provide the exact Plan Digest from your reviewed report. This ensures that no destructive operations occur if the repository state drifts (e.g., if a worktree becomes dirty or a ref advances).
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ace-git-worktree cleanup --target main --apply --approved-digest <sha256-digest>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
ACE will:
|
|
41
|
+
1. Re-scan the repository and rebuild the plan.
|
|
42
|
+
2. Abort if the new plan's digest does not match your `--approved-digest`.
|
|
43
|
+
3. Apply deletions in a fixed order (worktrees, local refs, remote refs).
|
|
44
|
+
4. Re-validate dirty state and expected SHAs immediately before each deletion.
|
|
45
|
+
5. Finish with a strict rescan and output the results.
|
|
46
|
+
|
|
47
|
+
### Strict Rescan
|
|
48
|
+
|
|
49
|
+
If you want to ensure that *only* the target branch remains after cleanup, you can use the `--require-only-target` flag:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ace-git-worktree cleanup --target main --apply --approved-digest <sha256-digest> --require-only-target
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If any non-target worktrees or refs are retained (e.g., because they were unproven or dirty), the command will exit with an error.
|
|
56
|
+
|
|
57
|
+
## Advanced Usage
|
|
58
|
+
|
|
59
|
+
For automation or scripting, use the JSON format:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
ace-git-worktree cleanup --target main --format json | jq .
|
|
63
|
+
```
|
|
@@ -126,6 +126,12 @@ ace-git-worktree remove feature-branch
|
|
|
126
126
|
# Skip automatic mise trust
|
|
127
127
|
ace-git-worktree create --task 081 --no-mise-trust
|
|
128
128
|
|
|
129
|
+
# Skip bootstrap command execution
|
|
130
|
+
ace-git-worktree create --task 081 --no-bootstrap
|
|
131
|
+
|
|
132
|
+
# Rerun preparation phases (toolchain trust and bootstrap policy) on existing worktree
|
|
133
|
+
ace-git-worktree bootstrap 081
|
|
134
|
+
|
|
129
135
|
# Skip task status update
|
|
130
136
|
ace-git-worktree create --task 081 --no-status-update
|
|
131
137
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require_relative "shared_helpers"
|
|
5
|
+
require_relative "../../commands/bootstrap_command"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Git
|
|
9
|
+
module Worktree
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
class Bootstrap < Ace::Support::Cli::Command
|
|
13
|
+
include SharedHelpers
|
|
14
|
+
|
|
15
|
+
desc "Rerun preparation phases (toolchain trust and bootstrap policy) for an existing worktree"
|
|
16
|
+
|
|
17
|
+
example [
|
|
18
|
+
"081 # Rerun bootstrap for task 081",
|
|
19
|
+
"t.081 --json # Output retry status in JSON format"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
argument :identifier, required: true, desc: "Task ID, branch, or worktree identifier"
|
|
23
|
+
|
|
24
|
+
option :json, desc: "Format output as JSON", type: :boolean, aliases: []
|
|
25
|
+
option :verbose, desc: "Show verbose output", type: :boolean, aliases: ["-v"]
|
|
26
|
+
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
27
|
+
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
28
|
+
|
|
29
|
+
def call(identifier: nil, **options)
|
|
30
|
+
display_config_summary("bootstrap", options)
|
|
31
|
+
|
|
32
|
+
args = []
|
|
33
|
+
args << identifier if identifier
|
|
34
|
+
args << "--json" if options[:json]
|
|
35
|
+
|
|
36
|
+
Ace::Git::Worktree::Commands::BootstrapCommand.new.run(args)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require_relative "shared_helpers"
|
|
5
|
+
require_relative "../../commands/cleanup_command"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Git
|
|
9
|
+
module Worktree
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
class Cleanup < Ace::Support::Cli::Command
|
|
13
|
+
include SharedHelpers
|
|
14
|
+
|
|
15
|
+
desc "Report cleanup plan for merged worktrees and refs"
|
|
16
|
+
|
|
17
|
+
example [
|
|
18
|
+
"--target main # Report against main",
|
|
19
|
+
"--target main --format json # JSON output",
|
|
20
|
+
"--target main --offline # Skip remote refresh"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
option :target, desc: "Target ref for ancestry proof (required)", type: :string, aliases: []
|
|
24
|
+
option :remote, desc: "Remote name (default: origin)", type: :string, default: "origin", aliases: []
|
|
25
|
+
option :offline, desc: "Skip remote evidence refresh", type: :boolean, aliases: []
|
|
26
|
+
option :apply, desc: "Apply a reviewed plan", type: :boolean, aliases: []
|
|
27
|
+
option :approved_digest, desc: "Approved plan digest to apply", type: :string, aliases: []
|
|
28
|
+
option :require_only_target, desc: "Fail if final rescan has retained non-target state", type: :boolean, aliases: []
|
|
29
|
+
option :format, desc: "Output format (table, json)", type: :string, default: "table", aliases: []
|
|
30
|
+
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
31
|
+
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
32
|
+
|
|
33
|
+
def call(**options)
|
|
34
|
+
display_config_summary("cleanup", options)
|
|
35
|
+
|
|
36
|
+
args = options_to_args(options)
|
|
37
|
+
|
|
38
|
+
Ace::Git::Worktree::Commands::CleanupCommand.new.run(args)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -23,11 +23,19 @@ module Ace
|
|
|
23
23
|
|
|
24
24
|
# Accept extra positional arguments for backward compatibility
|
|
25
25
|
# (e.g., "show", "validate" as positional args instead of flags)
|
|
26
|
-
argument :subcommand, required: false, desc: "Subcommand (show, validate, files)"
|
|
26
|
+
argument :subcommand, required: false, desc: "Subcommand (init, set-bootstrap, show, validate, files)"
|
|
27
27
|
|
|
28
28
|
option :show, desc: "Show current configuration", type: :boolean, aliases: []
|
|
29
29
|
option :validate, desc: "Validate configuration", type: :boolean, aliases: []
|
|
30
30
|
option :files, desc: "Show configuration file locations", type: :boolean, aliases: []
|
|
31
|
+
option :json, desc: "Format output as JSON", type: :boolean, aliases: []
|
|
32
|
+
option :bootstrap, desc: "Validate bootstrap policy", type: :boolean, aliases: []
|
|
33
|
+
option :command, desc: "Bootstrap command to execute", type: :string, aliases: []
|
|
34
|
+
option :working_dir, desc: "Working directory for bootstrap command", type: :string, aliases: []
|
|
35
|
+
option :timeout, desc: "Timeout in seconds for bootstrap command", type: :string, aliases: []
|
|
36
|
+
option :required, desc: "Require bootstrap execution to succeed", type: :boolean, aliases: []
|
|
37
|
+
option :advisory, desc: "Allow worktree creation when bootstrap fails", type: :boolean, aliases: []
|
|
38
|
+
option :env, desc: "Environment variables KEY=VALUE", type: :array, aliases: []
|
|
31
39
|
option :verbose, desc: "Show verbose output", type: :boolean, aliases: ["-v"]
|
|
32
40
|
option :quiet, type: :boolean, aliases: ["-q"], desc: "Suppress non-essential output"
|
|
33
41
|
option :debug, type: :boolean, aliases: ["-d"], desc: "Show debug output"
|
|
@@ -35,10 +43,25 @@ module Ace
|
|
|
35
43
|
def call(subcommand: nil, **options)
|
|
36
44
|
display_config_summary("config", options)
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
args = options_to_args(options)
|
|
40
|
-
# Add subcommand as positional argument if provided
|
|
46
|
+
args = []
|
|
41
47
|
args << subcommand if subcommand
|
|
48
|
+
args << "init" if options[:init]
|
|
49
|
+
args << "set-bootstrap" if options[:set_bootstrap]
|
|
50
|
+
args << "--show" if options[:show]
|
|
51
|
+
args << "--validate" if options[:validate]
|
|
52
|
+
args << "--files" if options[:files]
|
|
53
|
+
args << "--json" if options[:json]
|
|
54
|
+
args << "--bootstrap" if options[:bootstrap]
|
|
55
|
+
args << "--command" << options[:command] if options[:command]
|
|
56
|
+
args << "--working-dir" << options[:working_dir] if options[:working_dir]
|
|
57
|
+
args << "--timeout" << options[:timeout].to_s if options[:timeout]
|
|
58
|
+
args << "--required" if options[:required]
|
|
59
|
+
args << "--advisory" if options[:advisory]
|
|
60
|
+
if options[:env]
|
|
61
|
+
Array(options[:env]).each do |e|
|
|
62
|
+
args << "--env" << e
|
|
63
|
+
end
|
|
64
|
+
end
|
|
42
65
|
|
|
43
66
|
Ace::Git::Worktree::Commands::ConfigCommand.new.run(args)
|
|
44
67
|
end
|
|
@@ -49,6 +49,7 @@ module Ace
|
|
|
49
49
|
option :no_push, desc: "Skip pushing task changes", type: :boolean, aliases: ["--no-push"]
|
|
50
50
|
option :no_upstream, desc: "Skip pushing with upstream tracking", type: :boolean, aliases: ["--no-upstream"]
|
|
51
51
|
option :no_pr, desc: "Skip creating draft PR", type: :boolean
|
|
52
|
+
option :no_bootstrap, desc: "Skip worktree bootstrap preparation", type: :boolean
|
|
52
53
|
option :push_remote, desc: "Remote to push to", aliases: []
|
|
53
54
|
option :no_auto_navigate, desc: "Stay in current directory", type: :boolean, aliases: ["--no-auto-navigate"]
|
|
54
55
|
option :commit_message, desc: "Custom commit message", aliases: []
|
data/lib/ace/git/worktree/cli.rb
CHANGED
|
@@ -9,6 +9,8 @@ require_relative "cli/commands/switch"
|
|
|
9
9
|
require_relative "cli/commands/remove"
|
|
10
10
|
require_relative "cli/commands/prune"
|
|
11
11
|
require_relative "cli/commands/config"
|
|
12
|
+
require_relative "cli/commands/cleanup"
|
|
13
|
+
require_relative "cli/commands/bootstrap"
|
|
12
14
|
require "ace/core"
|
|
13
15
|
require "ace/support/cli"
|
|
14
16
|
|
|
@@ -29,6 +31,8 @@ module Ace
|
|
|
29
31
|
["switch", "Resolve a worktree path for cd navigation"],
|
|
30
32
|
["remove", "Remove a worktree by task, branch, or path"],
|
|
31
33
|
["prune", "Prune stale/deleted worktree references"],
|
|
34
|
+
["cleanup", "Report cleanup plan for merged worktrees and refs"],
|
|
35
|
+
["bootstrap", "Rerun preparation phases for an existing worktree"],
|
|
32
36
|
["config", "Show and validate configuration"]
|
|
33
37
|
].freeze
|
|
34
38
|
|
|
@@ -78,6 +82,8 @@ module Ace
|
|
|
78
82
|
register "switch", wrap_command(CLI::Commands::Switch), aliases: ["cd"]
|
|
79
83
|
register "remove", wrap_command(CLI::Commands::Remove), aliases: ["rm"]
|
|
80
84
|
register "prune", wrap_command(CLI::Commands::Prune), aliases: []
|
|
85
|
+
register "cleanup", wrap_command(CLI::Commands::Cleanup), aliases: []
|
|
86
|
+
register "bootstrap", wrap_command(CLI::Commands::Bootstrap), aliases: []
|
|
81
87
|
register "config", wrap_command(CLI::Commands::Config), aliases: []
|
|
82
88
|
|
|
83
89
|
# Version command
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require_relative "../organisms/worktree_manager"
|
|
5
|
+
require_relative "../molecules/toolchain_truster"
|
|
6
|
+
require_relative "../molecules/bootstrap_executor"
|
|
7
|
+
require_relative "../molecules/config_loader"
|
|
8
|
+
|
|
9
|
+
module Ace
|
|
10
|
+
module Git
|
|
11
|
+
module Worktree
|
|
12
|
+
module Commands
|
|
13
|
+
# Bootstrap command
|
|
14
|
+
#
|
|
15
|
+
# Reruns recoverable preparation phases (toolchain trust and bootstrap policy)
|
|
16
|
+
# for an existing worktree in place.
|
|
17
|
+
class BootstrapCommand
|
|
18
|
+
def initialize(manager: nil)
|
|
19
|
+
@manager = manager || Ace::Git::Worktree::Organisms::WorktreeManager.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Run bootstrap retry on existing worktree
|
|
23
|
+
#
|
|
24
|
+
# @param args [Array<String>] Arguments including identifier and optional flags
|
|
25
|
+
# @return [Integer] Exit code
|
|
26
|
+
def run(args = [])
|
|
27
|
+
options = parse_arguments(args)
|
|
28
|
+
return show_help if options[:help] || options[:identifier].nil?
|
|
29
|
+
|
|
30
|
+
worktree_info = find_target_worktree(options[:identifier])
|
|
31
|
+
unless worktree_info
|
|
32
|
+
puts "Error: Worktree matching '#{options[:identifier]}' not found."
|
|
33
|
+
return 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
wt_path = worktree_info[:path]
|
|
37
|
+
project_root = Dir.pwd
|
|
38
|
+
config = Molecules::ConfigLoader.new(project_root).load_without_validation
|
|
39
|
+
|
|
40
|
+
# Phase 1: Toolchain Trust
|
|
41
|
+
truster = Molecules::ToolchainTruster.new(project_root: wt_path, policy: "required")
|
|
42
|
+
trust_res = truster.verify_and_trust
|
|
43
|
+
|
|
44
|
+
# Phase 2: Bootstrap execution
|
|
45
|
+
executor = Molecules::BootstrapExecutor.new(
|
|
46
|
+
project_root: project_root,
|
|
47
|
+
worktree_path: wt_path,
|
|
48
|
+
bootstrap_config: config.bootstrap,
|
|
49
|
+
no_bootstrap: options[:no_bootstrap] || false
|
|
50
|
+
)
|
|
51
|
+
bootstrap_res = executor.run
|
|
52
|
+
|
|
53
|
+
phases = [trust_res, bootstrap_res]
|
|
54
|
+
|
|
55
|
+
req_failed = phases.any? { |p| p[:status] == "required_failed" }
|
|
56
|
+
adv_failed = phases.any? { |p| p[:status] == "advisory_failed" }
|
|
57
|
+
|
|
58
|
+
readiness = if req_failed
|
|
59
|
+
"not_ready"
|
|
60
|
+
elsif adv_failed
|
|
61
|
+
"ready_with_warning"
|
|
62
|
+
else
|
|
63
|
+
"ready"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
result = {
|
|
67
|
+
identifier: options[:identifier],
|
|
68
|
+
worktree_path: wt_path,
|
|
69
|
+
branch: worktree_info[:branch],
|
|
70
|
+
readiness: readiness,
|
|
71
|
+
phases: phases,
|
|
72
|
+
retry_command: (readiness == "not_ready") ? "ace-git-worktree bootstrap #{options[:identifier]}" : nil
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if options[:json]
|
|
76
|
+
puts JSON.pretty_generate(result)
|
|
77
|
+
else
|
|
78
|
+
puts "Worktree Preparation Retry: #{wt_path}"
|
|
79
|
+
puts "Readiness: #{readiness}"
|
|
80
|
+
puts
|
|
81
|
+
puts "Phases:"
|
|
82
|
+
phases.each do |p|
|
|
83
|
+
st = p[:status]
|
|
84
|
+
icon = case st
|
|
85
|
+
when "succeeded", "not_applicable" then "✓"
|
|
86
|
+
when "skipped" then "↷"
|
|
87
|
+
when "advisory_failed" then "⚠️"
|
|
88
|
+
else "❌"
|
|
89
|
+
end
|
|
90
|
+
puts " #{icon} #{p[:phase]}: #{st}"
|
|
91
|
+
puts " Command: #{p[:command]}" if p[:command]
|
|
92
|
+
puts " Output: #{p[:output]}" if p[:output] && !p[:output].empty? && st.include?("failed")
|
|
93
|
+
end
|
|
94
|
+
if readiness == "not_ready"
|
|
95
|
+
puts
|
|
96
|
+
puts "Retry with: ace-git-worktree bootstrap #{options[:identifier]}"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
(readiness == "not_ready") ? 1 : 0
|
|
101
|
+
rescue => e
|
|
102
|
+
puts "Error: #{e.message}"
|
|
103
|
+
1
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def show_help
|
|
107
|
+
puts <<~HELP
|
|
108
|
+
ace-git-worktree bootstrap - Rerun preparation phases on existing worktree
|
|
109
|
+
|
|
110
|
+
USAGE:
|
|
111
|
+
ace-git-worktree bootstrap <identifier> [OPTIONS]
|
|
112
|
+
|
|
113
|
+
OPTIONS:
|
|
114
|
+
--json Output format as JSON
|
|
115
|
+
--help, -h Show this help message
|
|
116
|
+
|
|
117
|
+
EXAMPLES:
|
|
118
|
+
ace-git-worktree bootstrap 081
|
|
119
|
+
ace-git-worktree bootstrap t.8vb.t.vyz.2 --json
|
|
120
|
+
HELP
|
|
121
|
+
0
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def parse_arguments(args)
|
|
127
|
+
options = {identifier: nil, json: false, help: false}
|
|
128
|
+
i = 0
|
|
129
|
+
while i < args.length
|
|
130
|
+
arg = args[i]
|
|
131
|
+
case arg
|
|
132
|
+
when "--json"
|
|
133
|
+
options[:json] = true
|
|
134
|
+
when "--help", "-h"
|
|
135
|
+
options[:help] = true
|
|
136
|
+
when /^--/
|
|
137
|
+
raise ArgumentError, "Unknown option: #{arg}"
|
|
138
|
+
else
|
|
139
|
+
options[:identifier] = arg if options[:identifier].nil?
|
|
140
|
+
end
|
|
141
|
+
i += 1
|
|
142
|
+
end
|
|
143
|
+
options
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def find_target_worktree(identifier)
|
|
147
|
+
worktrees = @manager.list[:worktrees] || []
|
|
148
|
+
worktrees.find do |wt|
|
|
149
|
+
wt[:path]&.end_with?("/#{identifier}") ||
|
|
150
|
+
wt[:path]&.include?("/t.#{identifier}") ||
|
|
151
|
+
wt[:branch]&.include?(identifier) ||
|
|
152
|
+
wt[:task_id] == identifier
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|