aidp 0.15.1 → 0.16.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +47 -0
  3. data/lib/aidp/analyze/error_handler.rb +14 -15
  4. data/lib/aidp/analyze/runner.rb +27 -5
  5. data/lib/aidp/analyze/steps.rb +4 -0
  6. data/lib/aidp/cli/jobs_command.rb +2 -1
  7. data/lib/aidp/cli.rb +853 -6
  8. data/lib/aidp/concurrency/backoff.rb +148 -0
  9. data/lib/aidp/concurrency/exec.rb +192 -0
  10. data/lib/aidp/concurrency/wait.rb +148 -0
  11. data/lib/aidp/concurrency.rb +71 -0
  12. data/lib/aidp/config.rb +20 -0
  13. data/lib/aidp/daemon/runner.rb +9 -8
  14. data/lib/aidp/debug_mixin.rb +1 -0
  15. data/lib/aidp/errors.rb +12 -0
  16. data/lib/aidp/execute/interactive_repl.rb +102 -11
  17. data/lib/aidp/execute/repl_macros.rb +776 -2
  18. data/lib/aidp/execute/runner.rb +27 -5
  19. data/lib/aidp/execute/steps.rb +2 -0
  20. data/lib/aidp/harness/config_loader.rb +24 -2
  21. data/lib/aidp/harness/enhanced_runner.rb +16 -2
  22. data/lib/aidp/harness/error_handler.rb +1 -1
  23. data/lib/aidp/harness/provider_info.rb +20 -16
  24. data/lib/aidp/harness/provider_manager.rb +56 -49
  25. data/lib/aidp/harness/runner.rb +3 -11
  26. data/lib/aidp/harness/state/persistence.rb +1 -6
  27. data/lib/aidp/harness/state_manager.rb +115 -7
  28. data/lib/aidp/harness/status_display.rb +11 -18
  29. data/lib/aidp/harness/ui/navigation/submenu.rb +1 -0
  30. data/lib/aidp/harness/ui/workflow_controller.rb +1 -1
  31. data/lib/aidp/harness/user_interface.rb +12 -15
  32. data/lib/aidp/init/doc_generator.rb +75 -10
  33. data/lib/aidp/init/project_analyzer.rb +154 -26
  34. data/lib/aidp/init/runner.rb +263 -10
  35. data/lib/aidp/jobs/background_runner.rb +15 -5
  36. data/lib/aidp/logger.rb +11 -0
  37. data/lib/aidp/providers/codex.rb +0 -1
  38. data/lib/aidp/providers/cursor.rb +0 -1
  39. data/lib/aidp/providers/github_copilot.rb +0 -1
  40. data/lib/aidp/providers/opencode.rb +0 -1
  41. data/lib/aidp/skills/composer.rb +178 -0
  42. data/lib/aidp/skills/loader.rb +205 -0
  43. data/lib/aidp/skills/registry.rb +220 -0
  44. data/lib/aidp/skills/skill.rb +174 -0
  45. data/lib/aidp/skills.rb +30 -0
  46. data/lib/aidp/version.rb +1 -1
  47. data/lib/aidp/watch/build_processor.rb +93 -28
  48. data/lib/aidp/watch/runner.rb +3 -2
  49. data/lib/aidp/workstream_executor.rb +244 -0
  50. data/lib/aidp/workstream_state.rb +212 -0
  51. data/lib/aidp/worktree.rb +208 -0
  52. data/lib/aidp.rb +6 -0
  53. metadata +17 -7
  54. data/lib/aidp/analyze/prioritizer.rb +0 -403
  55. data/lib/aidp/analyze/report_generator.rb +0 -582
  56. data/lib/aidp/cli/checkpoint_command.rb +0 -98
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+
6
+ module Aidp
7
+ # Manages per-workstream state (task, iterations, timestamps, event log)
8
+ # Stored under: .aidp/workstreams/<slug>/state.json and history.jsonl
9
+ module WorkstreamState
10
+ class Error < StandardError; end
11
+
12
+ class << self
13
+ def root_dir(project_dir)
14
+ File.join(project_dir, ".aidp", "workstreams")
15
+ end
16
+
17
+ def workstream_dir(slug, project_dir)
18
+ File.join(root_dir(project_dir), slug)
19
+ end
20
+
21
+ def state_file(slug, project_dir)
22
+ File.join(workstream_dir(slug, project_dir), "state.json")
23
+ end
24
+
25
+ def history_file(slug, project_dir)
26
+ File.join(workstream_dir(slug, project_dir), "history.jsonl")
27
+ end
28
+
29
+ # Per-worktree state files (mirrored for local inspection)
30
+ def worktree_state_file(slug, project_dir)
31
+ worktree_path = File.join(project_dir, ".worktrees", slug)
32
+ return nil unless Dir.exist?(worktree_path)
33
+ File.join(worktree_path, ".aidp", "workstreams", slug, "state.json")
34
+ end
35
+
36
+ def worktree_history_file(slug, project_dir)
37
+ worktree_path = File.join(project_dir, ".worktrees", slug)
38
+ return nil unless Dir.exist?(worktree_path)
39
+ File.join(worktree_path, ".aidp", "workstreams", slug, "history.jsonl")
40
+ end
41
+
42
+ # Initialize state for a new workstream
43
+ def init(slug:, project_dir:, task: nil)
44
+ dir = workstream_dir(slug, project_dir)
45
+ FileUtils.mkdir_p(dir)
46
+ now = Time.now.utc
47
+ state = {
48
+ slug: slug,
49
+ status: "active",
50
+ task: task,
51
+ started_at: now.iso8601,
52
+ updated_at: now.iso8601,
53
+ iterations: 0
54
+ }
55
+ write_json(state_file(slug, project_dir), state)
56
+ # Mirror to worktree if it exists
57
+ mirror_to_worktree(slug, project_dir, state)
58
+ append_event(slug: slug, project_dir: project_dir, type: "created", data: {task: task})
59
+ state
60
+ end
61
+
62
+ # Read current state (returns hash or nil)
63
+ def read(slug:, project_dir:)
64
+ file = state_file(slug, project_dir)
65
+ return nil unless File.exist?(file)
66
+ JSON.parse(File.read(file), symbolize_names: true)
67
+ rescue JSON::ParserError
68
+ nil
69
+ end
70
+
71
+ # Update selected attributes; updates updated_at automatically
72
+ def update(slug:, project_dir:, **attrs)
73
+ state = read(slug: slug, project_dir: project_dir) || init(slug: slug, project_dir: project_dir)
74
+ state.merge!(attrs.transform_keys(&:to_sym))
75
+ state[:updated_at] = Time.now.utc.iso8601
76
+ write_json(state_file(slug, project_dir), state)
77
+ # Mirror to worktree if it exists
78
+ mirror_to_worktree(slug, project_dir, state)
79
+ state
80
+ end
81
+
82
+ # Increment iteration counter and record event
83
+ def increment_iteration(slug:, project_dir:)
84
+ state = read(slug: slug, project_dir: project_dir) || init(slug: slug, project_dir: project_dir)
85
+ state[:iterations] = (state[:iterations] || 0) + 1
86
+ state[:updated_at] = Time.now.utc.iso8601
87
+ # Update status to active if paused (auto-resume on iteration)
88
+ state[:status] = "active" if state[:status] == "paused"
89
+ write_json(state_file(slug, project_dir), state)
90
+ # Mirror to worktree if it exists
91
+ mirror_to_worktree(slug, project_dir, state)
92
+ append_event(slug: slug, project_dir: project_dir, type: "iteration", data: {count: state[:iterations]})
93
+ state
94
+ end
95
+
96
+ # Append event to history.jsonl
97
+ def append_event(slug:, project_dir:, type:, data: {})
98
+ file = history_file(slug, project_dir)
99
+ FileUtils.mkdir_p(File.dirname(file))
100
+ event = {
101
+ timestamp: Time.now.utc.iso8601,
102
+ type: type,
103
+ data: data
104
+ }
105
+ File.open(file, "a") { |f| f.puts(JSON.generate(event)) }
106
+ # Mirror to worktree if it exists
107
+ wt_file = worktree_history_file(slug, project_dir)
108
+ if wt_file
109
+ FileUtils.mkdir_p(File.dirname(wt_file))
110
+ File.open(wt_file, "a") { |f| f.puts(JSON.generate(event)) }
111
+ end
112
+ event
113
+ end
114
+
115
+ # Read recent N events
116
+ def recent_events(slug:, project_dir:, limit: 5)
117
+ file = history_file(slug, project_dir)
118
+ return [] unless File.exist?(file)
119
+ lines = File.readlines(file, chomp: true)
120
+ lines.last(limit).map do |line|
121
+ JSON.parse(line, symbolize_names: true)
122
+ rescue JSON::ParserError
123
+ nil
124
+ end.compact
125
+ end
126
+
127
+ def elapsed_seconds(slug:, project_dir:)
128
+ state = read(slug: slug, project_dir: project_dir)
129
+ return 0 unless state && state[:started_at]
130
+ (Time.now.utc - Time.parse(state[:started_at])).to_i
131
+ end
132
+
133
+ # Check if workstream appears stalled (no activity for threshold seconds)
134
+ def stalled?(slug:, project_dir:, threshold_seconds: 3600)
135
+ state = read(slug: slug, project_dir: project_dir)
136
+ return false unless state && state[:updated_at]
137
+ return false if state[:status] != "active" # Only check active workstreams
138
+ (Time.now.utc - Time.parse(state[:updated_at])).to_i > threshold_seconds
139
+ end
140
+
141
+ # Auto-complete stalled workstreams
142
+ def auto_complete_stalled(slug:, project_dir:, threshold_seconds: 3600)
143
+ return unless stalled?(slug: slug, project_dir: project_dir, threshold_seconds: threshold_seconds)
144
+ complete(slug: slug, project_dir: project_dir)
145
+ append_event(slug: slug, project_dir: project_dir, type: "auto_completed", data: {reason: "stalled"})
146
+ end
147
+
148
+ def mark_removed(slug:, project_dir:)
149
+ state = read(slug: slug, project_dir: project_dir)
150
+ # Auto-complete if active when removing
151
+ if state && state[:status] == "active"
152
+ complete(slug: slug, project_dir: project_dir)
153
+ end
154
+ update(slug: slug, project_dir: project_dir, status: "removed")
155
+ append_event(slug: slug, project_dir: project_dir, type: "removed", data: {})
156
+ end
157
+
158
+ # Pause workstream (stop iteration without completion)
159
+ def pause(slug:, project_dir:)
160
+ state = read(slug: slug, project_dir: project_dir)
161
+ return {error: "Workstream not found"} unless state
162
+ return {error: "Already paused"} if state[:status] == "paused"
163
+
164
+ now = Time.now.utc.iso8601
165
+ update(slug: slug, project_dir: project_dir, status: "paused", paused_at: now)
166
+ append_event(slug: slug, project_dir: project_dir, type: "paused", data: {})
167
+ {status: "paused"}
168
+ end
169
+
170
+ # Resume workstream (return to active status)
171
+ def resume(slug:, project_dir:)
172
+ state = read(slug: slug, project_dir: project_dir)
173
+ return {error: "Workstream not found"} unless state
174
+ return {error: "Not paused"} unless state[:status] == "paused"
175
+
176
+ now = Time.now.utc.iso8601
177
+ update(slug: slug, project_dir: project_dir, status: "active", resumed_at: now)
178
+ append_event(slug: slug, project_dir: project_dir, type: "resumed", data: {})
179
+ {status: "active"}
180
+ end
181
+
182
+ # Mark workstream as completed
183
+ def complete(slug:, project_dir:)
184
+ state = read(slug: slug, project_dir: project_dir)
185
+ return {error: "Workstream not found"} unless state
186
+ return {error: "Already completed"} if state[:status] == "completed"
187
+
188
+ now = Time.now.utc.iso8601
189
+ update(slug: slug, project_dir: project_dir, status: "completed", completed_at: now)
190
+ append_event(slug: slug, project_dir: project_dir, type: "completed", data: {iterations: state[:iterations]})
191
+ {status: "completed"}
192
+ end
193
+
194
+ private
195
+
196
+ def write_json(path, obj)
197
+ File.write(path, JSON.pretty_generate(obj))
198
+ end
199
+
200
+ # Mirror state to worktree's .aidp directory for local visibility
201
+ def mirror_to_worktree(slug, project_dir, state)
202
+ wt_file = worktree_state_file(slug, project_dir)
203
+ return unless wt_file
204
+ FileUtils.mkdir_p(File.dirname(wt_file))
205
+ write_json(wt_file, state)
206
+ rescue
207
+ # Silently ignore mirroring errors to not disrupt main operation
208
+ nil
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "json"
5
+ require_relative "workstream_state"
6
+
7
+ module Aidp
8
+ # Manages git worktree operations for parallel workstreams.
9
+ # Each workstream gets an isolated git worktree with its own branch,
10
+ # allowing multiple agents to work concurrently without conflicts.
11
+ module Worktree
12
+ class Error < StandardError; end
13
+ class NotInGitRepo < Error; end
14
+ class WorktreeExists < Error; end
15
+ class WorktreeNotFound < Error; end
16
+
17
+ class << self
18
+ # Create a new git worktree for a workstream
19
+ #
20
+ # @param slug [String] Short identifier for this workstream (e.g., "iss-123-fix-login")
21
+ # @param project_dir [String] Project root directory
22
+ # @param branch [String, nil] Branch name (defaults to "aidp/#{slug}")
23
+ # @param base_branch [String] Branch to create from (defaults to current branch)
24
+ # @return [Hash] Worktree info: { path:, branch:, slug: }
25
+ def create(slug:, project_dir: Dir.pwd, branch: nil, base_branch: nil, task: nil)
26
+ ensure_git_repo!(project_dir)
27
+
28
+ branch ||= "aidp/#{slug}"
29
+ worktree_path = worktree_path_for(slug, project_dir)
30
+
31
+ if Dir.exist?(worktree_path)
32
+ raise WorktreeExists, "Worktree already exists at #{worktree_path}"
33
+ end
34
+
35
+ # Create the worktree
36
+ cmd = ["git", "worktree", "add", "-b", branch, worktree_path]
37
+ cmd << base_branch if base_branch
38
+
39
+ Dir.chdir(project_dir) do
40
+ success = system(*cmd, out: File::NULL, err: File::NULL)
41
+ unless success
42
+ raise Error, "Failed to create worktree: #{$?.exitstatus}"
43
+ end
44
+ end
45
+
46
+ # Initialize .aidp directory in the worktree
47
+ ensure_aidp_dir(worktree_path)
48
+
49
+ # Register the worktree
50
+ register_worktree(slug, worktree_path, branch, project_dir)
51
+
52
+ # Initialize per-workstream state (task, counters, events)
53
+ Aidp::WorkstreamState.init(slug: slug, project_dir: project_dir, task: task)
54
+
55
+ {
56
+ slug: slug,
57
+ path: worktree_path,
58
+ branch: branch
59
+ }
60
+ end
61
+
62
+ # List all active worktrees for this project
63
+ #
64
+ # @param project_dir [String] Project root directory
65
+ # @return [Array<Hash>] Array of worktree info hashes
66
+ def list(project_dir: Dir.pwd)
67
+ registry = load_registry(project_dir)
68
+ registry.map do |slug, info|
69
+ {
70
+ slug: slug,
71
+ path: info["path"],
72
+ branch: info["branch"],
73
+ created_at: info["created_at"],
74
+ active: Dir.exist?(info["path"])
75
+ }
76
+ end
77
+ end
78
+
79
+ # Remove a worktree and optionally its branch
80
+ #
81
+ # @param slug [String] Workstream identifier
82
+ # @param project_dir [String] Project root directory
83
+ # @param delete_branch [Boolean] Whether to delete the git branch
84
+ def remove(slug:, project_dir: Dir.pwd, delete_branch: false)
85
+ registry = load_registry(project_dir)
86
+ info = registry[slug]
87
+
88
+ raise WorktreeNotFound, "Worktree '#{slug}' not found" unless info
89
+
90
+ worktree_path = info["path"]
91
+ branch = info["branch"]
92
+
93
+ # Remove the git worktree
94
+ if Dir.exist?(worktree_path)
95
+ Dir.chdir(project_dir) do
96
+ system("git", "worktree", "remove", worktree_path, "--force", out: File::NULL, err: File::NULL)
97
+ end
98
+ end
99
+
100
+ # Remove the branch if requested
101
+ if delete_branch
102
+ Dir.chdir(project_dir) do
103
+ system("git", "branch", "-D", branch, out: File::NULL, err: File::NULL)
104
+ end
105
+ end
106
+
107
+ # Mark state removed (if exists) then unregister
108
+ if Aidp::WorkstreamState.read(slug: slug, project_dir: project_dir)
109
+ Aidp::WorkstreamState.mark_removed(slug: slug, project_dir: project_dir)
110
+ end
111
+ # Unregister the worktree
112
+ unregister_worktree(slug, project_dir)
113
+
114
+ true
115
+ end
116
+
117
+ # Get info for a specific worktree
118
+ #
119
+ # @param slug [String] Workstream identifier
120
+ # @param project_dir [String] Project root directory
121
+ # @return [Hash, nil] Worktree info or nil if not found
122
+ def info(slug:, project_dir: Dir.pwd)
123
+ registry = load_registry(project_dir)
124
+ data = registry[slug]
125
+ return nil unless data
126
+
127
+ {
128
+ slug: slug,
129
+ path: data["path"],
130
+ branch: data["branch"],
131
+ created_at: data["created_at"],
132
+ active: Dir.exist?(data["path"])
133
+ }
134
+ end
135
+
136
+ # Check if a worktree exists
137
+ #
138
+ # @param slug [String] Workstream identifier
139
+ # @param project_dir [String] Project root directory
140
+ # @return [Boolean]
141
+ def exists?(slug:, project_dir: Dir.pwd)
142
+ !info(slug: slug, project_dir: project_dir).nil?
143
+ end
144
+
145
+ private
146
+
147
+ # Ensure we're in a git repository
148
+ def ensure_git_repo!(project_dir)
149
+ Dir.chdir(project_dir) do
150
+ unless system("git", "rev-parse", "--git-dir", out: File::NULL, err: File::NULL)
151
+ raise NotInGitRepo, "Not in a git repository: #{project_dir}"
152
+ end
153
+ end
154
+ end
155
+
156
+ # Get the worktree path for a slug
157
+ def worktree_path_for(slug, project_dir)
158
+ File.join(project_dir, ".worktrees", slug)
159
+ end
160
+
161
+ # Ensure the .aidp directory exists in a worktree
162
+ def ensure_aidp_dir(worktree_path)
163
+ aidp_dir = File.join(worktree_path, ".aidp")
164
+ FileUtils.mkdir_p(aidp_dir) unless Dir.exist?(aidp_dir)
165
+ end
166
+
167
+ # Load the worktree registry
168
+ def load_registry(project_dir)
169
+ registry_file = registry_file_path(project_dir)
170
+ return {} unless File.exist?(registry_file)
171
+
172
+ JSON.parse(File.read(registry_file))
173
+ rescue JSON::ParserError
174
+ {}
175
+ end
176
+
177
+ # Save the worktree registry
178
+ def save_registry(registry, project_dir)
179
+ registry_file = registry_file_path(project_dir)
180
+ FileUtils.mkdir_p(File.dirname(registry_file))
181
+ File.write(registry_file, JSON.pretty_generate(registry))
182
+ end
183
+
184
+ # Register a new worktree
185
+ def register_worktree(slug, path, branch, project_dir)
186
+ registry = load_registry(project_dir)
187
+ registry[slug] = {
188
+ "path" => path,
189
+ "branch" => branch,
190
+ "created_at" => Time.now.utc.iso8601
191
+ }
192
+ save_registry(registry, project_dir)
193
+ end
194
+
195
+ # Unregister a worktree
196
+ def unregister_worktree(slug, project_dir)
197
+ registry = load_registry(project_dir)
198
+ registry.delete(slug)
199
+ save_registry(registry, project_dir)
200
+ end
201
+
202
+ # Path to the worktree registry file
203
+ def registry_file_path(project_dir)
204
+ File.join(project_dir, ".aidp", "worktrees.json")
205
+ end
206
+ end
207
+ end
208
+ end
data/lib/aidp.rb CHANGED
@@ -8,6 +8,7 @@ require_relative "aidp/version"
8
8
  require_relative "aidp/config"
9
9
  require_relative "aidp/util"
10
10
  require_relative "aidp/message_display"
11
+ require_relative "aidp/concurrency"
11
12
  require_relative "aidp/setup/wizard"
12
13
  require_relative "aidp/init"
13
14
  require_relative "aidp/watch"
@@ -69,6 +70,11 @@ require_relative "aidp/logger"
69
70
  require_relative "aidp/daemon/process_manager"
70
71
  require_relative "aidp/daemon/runner"
71
72
 
73
+ # Workstream/worktree management
74
+ require_relative "aidp/worktree"
75
+ require_relative "aidp/workstream_state"
76
+ require_relative "aidp/workstream_executor"
77
+
72
78
  # Harness mode
73
79
  require_relative "aidp/harness/configuration"
74
80
  require_relative "aidp/harness/config_schema"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aidp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan
@@ -10,19 +10,19 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: async-job
13
+ name: concurrent-ruby
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.11'
18
+ version: '1.3'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0.11'
25
+ version: '1.3'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: csv
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -237,9 +237,7 @@ files:
237
237
  - lib/aidp/analyze/feature_analyzer.rb
238
238
  - lib/aidp/analyze/json_file_storage.rb
239
239
  - lib/aidp/analyze/kb_inspector.rb
240
- - lib/aidp/analyze/prioritizer.rb
241
240
  - lib/aidp/analyze/progress.rb
242
- - lib/aidp/analyze/report_generator.rb
243
241
  - lib/aidp/analyze/ruby_maat_integration.rb
244
242
  - lib/aidp/analyze/runner.rb
245
243
  - lib/aidp/analyze/seams.rb
@@ -247,19 +245,23 @@ files:
247
245
  - lib/aidp/analyze/tree_sitter_grammar_loader.rb
248
246
  - lib/aidp/analyze/tree_sitter_scan.rb
249
247
  - lib/aidp/cli.rb
250
- - lib/aidp/cli/checkpoint_command.rb
251
248
  - lib/aidp/cli/enhanced_input.rb
252
249
  - lib/aidp/cli/first_run_wizard.rb
253
250
  - lib/aidp/cli/issue_importer.rb
254
251
  - lib/aidp/cli/jobs_command.rb
255
252
  - lib/aidp/cli/mcp_dashboard.rb
256
253
  - lib/aidp/cli/terminal_io.rb
254
+ - lib/aidp/concurrency.rb
255
+ - lib/aidp/concurrency/backoff.rb
256
+ - lib/aidp/concurrency/exec.rb
257
+ - lib/aidp/concurrency/wait.rb
257
258
  - lib/aidp/config.rb
258
259
  - lib/aidp/config/paths.rb
259
260
  - lib/aidp/core_ext/class_attribute.rb
260
261
  - lib/aidp/daemon/process_manager.rb
261
262
  - lib/aidp/daemon/runner.rb
262
263
  - lib/aidp/debug_mixin.rb
264
+ - lib/aidp/errors.rb
263
265
  - lib/aidp/execute/agent_signal_parser.rb
264
266
  - lib/aidp/execute/async_work_loop_runner.rb
265
267
  - lib/aidp/execute/checkpoint.rb
@@ -341,6 +343,11 @@ files:
341
343
  - lib/aidp/providers/opencode.rb
342
344
  - lib/aidp/rescue_logging.rb
343
345
  - lib/aidp/setup/wizard.rb
346
+ - lib/aidp/skills.rb
347
+ - lib/aidp/skills/composer.rb
348
+ - lib/aidp/skills/loader.rb
349
+ - lib/aidp/skills/registry.rb
350
+ - lib/aidp/skills/skill.rb
344
351
  - lib/aidp/storage/csv_storage.rb
345
352
  - lib/aidp/storage/file_manager.rb
346
353
  - lib/aidp/storage/json_storage.rb
@@ -357,6 +364,9 @@ files:
357
364
  - lib/aidp/workflows/definitions.rb
358
365
  - lib/aidp/workflows/guided_agent.rb
359
366
  - lib/aidp/workflows/selector.rb
367
+ - lib/aidp/workstream_executor.rb
368
+ - lib/aidp/workstream_state.rb
369
+ - lib/aidp/worktree.rb
360
370
  - templates/COMMON/AGENT_BASE.md
361
371
  - templates/COMMON/CONVENTIONS.md
362
372
  - templates/COMMON/TEMPLATES/ADR_TEMPLATE.md