aidp 0.16.0 → 0.17.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/lib/aidp/analyze/error_handler.rb +32 -13
- data/lib/aidp/analyze/progress.rb +1 -1
- data/lib/aidp/cli.rb +280 -7
- data/lib/aidp/config.rb +1 -1
- data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
- data/lib/aidp/execute/checkpoint.rb +1 -1
- data/lib/aidp/execute/future_work_backlog.rb +1 -1
- data/lib/aidp/execute/progress.rb +1 -1
- data/lib/aidp/execute/repl_macros.rb +79 -10
- data/lib/aidp/harness/config_validator.rb +1 -1
- data/lib/aidp/jobs/background_runner.rb +1 -1
- data/lib/aidp/skills/registry.rb +31 -29
- data/lib/aidp/skills/router.rb +178 -0
- data/lib/aidp/skills/wizard/builder.rb +141 -0
- data/lib/aidp/skills/wizard/controller.rb +145 -0
- data/lib/aidp/skills/wizard/differ.rb +232 -0
- data/lib/aidp/skills/wizard/prompter.rb +317 -0
- data/lib/aidp/skills/wizard/template_library.rb +164 -0
- data/lib/aidp/skills/wizard/writer.rb +105 -0
- data/lib/aidp/version.rb +1 -1
- data/templates/skills/README.md +334 -0
- data/templates/skills/architecture_analyst/SKILL.md +173 -0
- data/templates/skills/product_strategist/SKILL.md +141 -0
- data/templates/skills/repository_analyst/SKILL.md +117 -0
- data/templates/skills/test_analyzer/SKILL.md +213 -0
- metadata +13 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84451cdcc0886f1a70e799ab53d9b8898633f324cdd80c5f07a5f204848a3de2
|
|
4
|
+
data.tar.gz: e93982382c700564db24fac6ff1de2276e5b0301b91f6cade19aa8dfacd3f7d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3de783cb25c3eedc9056f77c2b294918a2f5ab46c009280897b6094dd157c45c681fc5c8fe22c6eea401ba74e0c4151c132a85e3c8ceedfef7722e9580f96f43
|
|
7
|
+
data.tar.gz: de86c77e08a8f9b837d501d8e69786b6f969c0e2a1538f1a9d2062267f01d6e8c855f0885c31d0bdc3f2c9362fa78439fccdcfe5e09a12cd1ab61282365cdc4a
|
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
require "logger"
|
|
4
4
|
require_relative "../concurrency"
|
|
5
5
|
|
|
6
|
+
begin
|
|
7
|
+
require "net/http"
|
|
8
|
+
rescue LoadError
|
|
9
|
+
# Net::HTTP might not be available in all environments
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
require "sqlite3"
|
|
14
|
+
rescue LoadError
|
|
15
|
+
# SQLite3 might not be available in all environments
|
|
16
|
+
end
|
|
17
|
+
|
|
6
18
|
module Aidp
|
|
7
19
|
module Analyze
|
|
8
20
|
# Comprehensive error handling system for analyze mode
|
|
@@ -24,7 +36,7 @@ module Aidp
|
|
|
24
36
|
context: context,
|
|
25
37
|
step: step,
|
|
26
38
|
retry_count: retry_count,
|
|
27
|
-
timestamp: Time.
|
|
39
|
+
timestamp: Time.now
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
log_error(error_info)
|
|
@@ -59,7 +71,7 @@ module Aidp
|
|
|
59
71
|
{
|
|
60
72
|
status: "skipped",
|
|
61
73
|
reason: error.message,
|
|
62
|
-
timestamp: Time.
|
|
74
|
+
timestamp: Time.now
|
|
63
75
|
}
|
|
64
76
|
end
|
|
65
77
|
|
|
@@ -88,8 +100,8 @@ module Aidp
|
|
|
88
100
|
|
|
89
101
|
def setup_logger(log_file, verbose)
|
|
90
102
|
output_stream = log_file || @output || $stdout
|
|
91
|
-
logger = Logger.new(output_stream)
|
|
92
|
-
logger.level = verbose ? Logger::DEBUG : Logger::INFO
|
|
103
|
+
logger = ::Logger.new(output_stream)
|
|
104
|
+
logger.level = verbose ? ::Logger::DEBUG : ::Logger::INFO
|
|
93
105
|
logger.formatter = proc do |severity, datetime, progname, msg|
|
|
94
106
|
"#{datetime.strftime("%Y-%m-%d %H:%M:%S")} [#{severity}] #{msg}\n"
|
|
95
107
|
end
|
|
@@ -97,19 +109,28 @@ module Aidp
|
|
|
97
109
|
end
|
|
98
110
|
|
|
99
111
|
def setup_recovery_strategies
|
|
100
|
-
{
|
|
101
|
-
Net::TimeoutError => :retry_with_backoff,
|
|
102
|
-
Net::HTTPError => :retry_with_backoff,
|
|
103
|
-
SocketError => :retry_with_backoff,
|
|
112
|
+
strategies = {
|
|
104
113
|
Errno::ENOENT => :skip_step_with_warning,
|
|
105
114
|
Errno::EACCES => :skip_step_with_warning,
|
|
106
115
|
Errno::ENOSPC => :critical_error,
|
|
107
|
-
SQLite3::BusyException => :retry_with_backoff,
|
|
108
|
-
SQLite3::CorruptException => :critical_error,
|
|
109
116
|
AnalysisTimeoutError => :chunk_and_retry,
|
|
110
117
|
AnalysisDataError => :continue_with_partial_data,
|
|
111
118
|
AnalysisToolError => :log_and_continue
|
|
112
119
|
}
|
|
120
|
+
|
|
121
|
+
# Add network error classes if available
|
|
122
|
+
strategies[Net::TimeoutError] = :retry_with_backoff if defined?(Net::TimeoutError)
|
|
123
|
+
|
|
124
|
+
strategies[Net::HTTPError] = :retry_with_backoff if defined?(Net::HTTPError)
|
|
125
|
+
|
|
126
|
+
strategies[SocketError] = :retry_with_backoff if defined?(SocketError)
|
|
127
|
+
|
|
128
|
+
# Add SQLite error classes if available
|
|
129
|
+
strategies[SQLite3::BusyException] = :retry_with_backoff if defined?(SQLite3::BusyException)
|
|
130
|
+
|
|
131
|
+
strategies[SQLite3::CorruptException] = :critical_error if defined?(SQLite3::CorruptException)
|
|
132
|
+
|
|
133
|
+
strategies
|
|
113
134
|
end
|
|
114
135
|
|
|
115
136
|
def log_error(error_info)
|
|
@@ -250,9 +271,7 @@ module Aidp
|
|
|
250
271
|
tool_name = context[:tool_name] || "analysis tool"
|
|
251
272
|
error_msg = "#{tool_name} failed: #{error.message}"
|
|
252
273
|
|
|
253
|
-
if context[:installation_guide]
|
|
254
|
-
error_msg += "\n\nTo install #{tool_name}:\n#{context[:installation_guide]}"
|
|
255
|
-
end
|
|
274
|
+
error_msg += "\n\nTo install #{tool_name}:\n#{context[:installation_guide]}" if context[:installation_guide]
|
|
256
275
|
|
|
257
276
|
raise AnalysisToolError.new(error_msg)
|
|
258
277
|
end
|
data/lib/aidp/cli.rb
CHANGED
|
@@ -241,7 +241,7 @@ module Aidp
|
|
|
241
241
|
|
|
242
242
|
if File.exist?(config_path)
|
|
243
243
|
require "yaml"
|
|
244
|
-
full_config = YAML.
|
|
244
|
+
full_config = YAML.safe_load_file(config_path, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
245
245
|
logging_config = full_config["logging"] || full_config[:logging] || {}
|
|
246
246
|
end
|
|
247
247
|
|
|
@@ -1722,10 +1722,10 @@ module Aidp
|
|
|
1722
1722
|
|
|
1723
1723
|
by_source = registry.by_source
|
|
1724
1724
|
|
|
1725
|
-
if by_source[:
|
|
1726
|
-
display_message("
|
|
1725
|
+
if by_source[:template].any?
|
|
1726
|
+
display_message("Template Skills", type: :highlight)
|
|
1727
1727
|
display_message("=" * 80, type: :muted)
|
|
1728
|
-
table_rows = by_source[:
|
|
1728
|
+
table_rows = by_source[:template].map do |skill_id|
|
|
1729
1729
|
skill = registry.find(skill_id)
|
|
1730
1730
|
[skill_id, skill.version, skill.description[0, 60]]
|
|
1731
1731
|
end
|
|
@@ -1735,10 +1735,10 @@ module Aidp
|
|
|
1735
1735
|
display_message("", type: :info)
|
|
1736
1736
|
end
|
|
1737
1737
|
|
|
1738
|
-
if by_source[:
|
|
1739
|
-
display_message("
|
|
1738
|
+
if by_source[:project].any?
|
|
1739
|
+
display_message("Project Skills", type: :highlight)
|
|
1740
1740
|
display_message("=" * 80, type: :muted)
|
|
1741
|
-
table_rows = by_source[:
|
|
1741
|
+
table_rows = by_source[:project].map do |skill_id|
|
|
1742
1742
|
skill = registry.find(skill_id)
|
|
1743
1743
|
[skill_id, skill.version, skill.description[0, 60]]
|
|
1744
1744
|
end
|
|
@@ -1846,6 +1846,204 @@ module Aidp
|
|
|
1846
1846
|
display_message("Failed to search skills: #{e.message}", type: :error)
|
|
1847
1847
|
end
|
|
1848
1848
|
|
|
1849
|
+
when "preview"
|
|
1850
|
+
# Preview full skill content
|
|
1851
|
+
skill_id = args.shift
|
|
1852
|
+
|
|
1853
|
+
unless skill_id
|
|
1854
|
+
display_message("Usage: aidp skill preview <skill-id>", type: :info)
|
|
1855
|
+
return
|
|
1856
|
+
end
|
|
1857
|
+
|
|
1858
|
+
begin
|
|
1859
|
+
registry = Aidp::Skills::Registry.new(project_dir: Dir.pwd)
|
|
1860
|
+
registry.load_skills
|
|
1861
|
+
|
|
1862
|
+
skill = registry.find(skill_id)
|
|
1863
|
+
|
|
1864
|
+
unless skill
|
|
1865
|
+
display_message("Skill not found: #{skill_id}", type: :error)
|
|
1866
|
+
display_message("Use 'aidp skill list' to see available skills", type: :muted)
|
|
1867
|
+
return
|
|
1868
|
+
end
|
|
1869
|
+
|
|
1870
|
+
require_relative "skills/wizard/builder"
|
|
1871
|
+
require_relative "skills/wizard/template_library"
|
|
1872
|
+
|
|
1873
|
+
builder = Aidp::Skills::Wizard::Builder.new
|
|
1874
|
+
full_content = builder.to_skill_md(skill)
|
|
1875
|
+
|
|
1876
|
+
# Check if this is a project skill with a matching template
|
|
1877
|
+
source_info = registry.by_source[skill_id]
|
|
1878
|
+
inheritance_info = ""
|
|
1879
|
+
if source_info == :project
|
|
1880
|
+
template_library = Aidp::Skills::Wizard::TemplateLibrary.new(project_dir: Dir.pwd)
|
|
1881
|
+
template_skill = template_library.templates.find { |s| s.id == skill.id }
|
|
1882
|
+
if template_skill
|
|
1883
|
+
inheritance_info = " (inherits from template)"
|
|
1884
|
+
end
|
|
1885
|
+
elsif source_info == :template
|
|
1886
|
+
inheritance_info = " (template)"
|
|
1887
|
+
end
|
|
1888
|
+
|
|
1889
|
+
display_message("\n" + "=" * 60, type: :info)
|
|
1890
|
+
display_message("Skill: #{skill.name} (#{skill.id}) v#{skill.version}#{inheritance_info}", type: :highlight)
|
|
1891
|
+
display_message("=" * 60 + "\n", type: :info)
|
|
1892
|
+
display_message(full_content, type: :info)
|
|
1893
|
+
display_message("\n" + "=" * 60, type: :info)
|
|
1894
|
+
rescue => e
|
|
1895
|
+
display_message("Failed to preview skill: #{e.message}", type: :error)
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
when "diff"
|
|
1899
|
+
# Show diff between project skill and template
|
|
1900
|
+
skill_id = args.shift
|
|
1901
|
+
|
|
1902
|
+
unless skill_id
|
|
1903
|
+
display_message("Usage: aidp skill diff <skill-id>", type: :info)
|
|
1904
|
+
return
|
|
1905
|
+
end
|
|
1906
|
+
|
|
1907
|
+
begin
|
|
1908
|
+
require_relative "skills/wizard/template_library"
|
|
1909
|
+
require_relative "skills/wizard/differ"
|
|
1910
|
+
|
|
1911
|
+
registry = Aidp::Skills::Registry.new(project_dir: Dir.pwd)
|
|
1912
|
+
registry.load_skills
|
|
1913
|
+
|
|
1914
|
+
project_skill = registry.find(skill_id)
|
|
1915
|
+
|
|
1916
|
+
unless project_skill
|
|
1917
|
+
display_message("Skill not found: #{skill_id}", type: :error)
|
|
1918
|
+
return
|
|
1919
|
+
end
|
|
1920
|
+
|
|
1921
|
+
# Check if it's a project skill
|
|
1922
|
+
unless registry.by_source[:project].include?(skill_id)
|
|
1923
|
+
display_message("Skill '#{skill_id}' is a template skill, not a project skill", type: :info)
|
|
1924
|
+
display_message("Only project skills can be diffed against templates", type: :muted)
|
|
1925
|
+
return
|
|
1926
|
+
end
|
|
1927
|
+
|
|
1928
|
+
# Find the template
|
|
1929
|
+
template_library = Aidp::Skills::Wizard::TemplateLibrary.new(project_dir: Dir.pwd)
|
|
1930
|
+
template_skill = template_library.find(skill_id)
|
|
1931
|
+
|
|
1932
|
+
unless template_skill
|
|
1933
|
+
display_message("No template found for skill '#{skill_id}'", type: :info)
|
|
1934
|
+
display_message("This is a custom skill without a template base", type: :muted)
|
|
1935
|
+
return
|
|
1936
|
+
end
|
|
1937
|
+
|
|
1938
|
+
# Show diff
|
|
1939
|
+
differ = Aidp::Skills::Wizard::Differ.new
|
|
1940
|
+
diff_result = differ.diff(template_skill, project_skill)
|
|
1941
|
+
differ.display(diff_result)
|
|
1942
|
+
rescue => e
|
|
1943
|
+
display_message("Failed to diff skill: #{e.message}", type: :error)
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1946
|
+
when "edit"
|
|
1947
|
+
# Edit an existing skill
|
|
1948
|
+
skill_id = args.shift
|
|
1949
|
+
|
|
1950
|
+
unless skill_id
|
|
1951
|
+
display_message("Usage: aidp skill edit <skill-id>", type: :info)
|
|
1952
|
+
return
|
|
1953
|
+
end
|
|
1954
|
+
|
|
1955
|
+
begin
|
|
1956
|
+
require_relative "skills/wizard/controller"
|
|
1957
|
+
|
|
1958
|
+
registry = Aidp::Skills::Registry.new(project_dir: Dir.pwd)
|
|
1959
|
+
registry.load_skills
|
|
1960
|
+
|
|
1961
|
+
skill = registry.find(skill_id)
|
|
1962
|
+
|
|
1963
|
+
unless skill
|
|
1964
|
+
display_message("Skill not found: #{skill_id}", type: :error)
|
|
1965
|
+
display_message("Use 'aidp skill list' to see available skills", type: :muted)
|
|
1966
|
+
return
|
|
1967
|
+
end
|
|
1968
|
+
|
|
1969
|
+
# Check if it's editable (must be project skill or willing to copy template)
|
|
1970
|
+
if registry.by_source[:template].include?(skill_id)
|
|
1971
|
+
display_message("'#{skill_id}' is a template skill", type: :info)
|
|
1972
|
+
display_message("Editing will create a project override in .aidp/skills/", type: :muted)
|
|
1973
|
+
end
|
|
1974
|
+
|
|
1975
|
+
# Parse options
|
|
1976
|
+
options = {}
|
|
1977
|
+
while args.first&.start_with?("--")
|
|
1978
|
+
opt = args.shift
|
|
1979
|
+
case opt
|
|
1980
|
+
when "--dry-run"
|
|
1981
|
+
options[:dry_run] = true
|
|
1982
|
+
when "--open-editor"
|
|
1983
|
+
options[:open_editor] = true
|
|
1984
|
+
else
|
|
1985
|
+
display_message("Unknown option: #{opt}", type: :error)
|
|
1986
|
+
return
|
|
1987
|
+
end
|
|
1988
|
+
end
|
|
1989
|
+
|
|
1990
|
+
# Pre-fill wizard with existing skill data
|
|
1991
|
+
options[:id] = skill.id
|
|
1992
|
+
options[:name] = skill.name
|
|
1993
|
+
options[:edit_mode] = true
|
|
1994
|
+
options[:existing_skill] = skill
|
|
1995
|
+
|
|
1996
|
+
# Run wizard in edit mode
|
|
1997
|
+
wizard = Aidp::Skills::Wizard::Controller.new(
|
|
1998
|
+
project_dir: Dir.pwd,
|
|
1999
|
+
options: options
|
|
2000
|
+
)
|
|
2001
|
+
wizard.run
|
|
2002
|
+
rescue => e
|
|
2003
|
+
display_message("Failed to edit skill: #{e.message}", type: :error)
|
|
2004
|
+
end
|
|
2005
|
+
|
|
2006
|
+
when "new"
|
|
2007
|
+
# Create a new skill using the wizard
|
|
2008
|
+
begin
|
|
2009
|
+
require_relative "skills/wizard/controller"
|
|
2010
|
+
|
|
2011
|
+
# Parse options
|
|
2012
|
+
options = {}
|
|
2013
|
+
while args.first&.start_with?("--")
|
|
2014
|
+
opt = args.shift
|
|
2015
|
+
case opt
|
|
2016
|
+
when "--minimal"
|
|
2017
|
+
options[:minimal] = true
|
|
2018
|
+
when "--dry-run"
|
|
2019
|
+
options[:dry_run] = true
|
|
2020
|
+
when "--yes", "-y"
|
|
2021
|
+
options[:yes] = true
|
|
2022
|
+
when "--id"
|
|
2023
|
+
options[:id] = args.shift
|
|
2024
|
+
when "--name"
|
|
2025
|
+
options[:name] = args.shift
|
|
2026
|
+
when "--from-template"
|
|
2027
|
+
options[:from_template] = args.shift
|
|
2028
|
+
when "--clone"
|
|
2029
|
+
options[:clone] = args.shift
|
|
2030
|
+
else
|
|
2031
|
+
display_message("Unknown option: #{opt}", type: :error)
|
|
2032
|
+
return
|
|
2033
|
+
end
|
|
2034
|
+
end
|
|
2035
|
+
|
|
2036
|
+
# Run wizard
|
|
2037
|
+
wizard = Aidp::Skills::Wizard::Controller.new(
|
|
2038
|
+
project_dir: Dir.pwd,
|
|
2039
|
+
options: options
|
|
2040
|
+
)
|
|
2041
|
+
wizard.run
|
|
2042
|
+
rescue => e
|
|
2043
|
+
display_message("Failed to create skill: #{e.message}", type: :error)
|
|
2044
|
+
Aidp.log_error("cli", "Skill wizard failed", error: e.message, backtrace: e.backtrace.first(5))
|
|
2045
|
+
end
|
|
2046
|
+
|
|
1849
2047
|
when "validate"
|
|
1850
2048
|
# Validate skill file format
|
|
1851
2049
|
skill_path = args.shift
|
|
@@ -1893,19 +2091,94 @@ module Aidp
|
|
|
1893
2091
|
end
|
|
1894
2092
|
end
|
|
1895
2093
|
|
|
2094
|
+
when "delete"
|
|
2095
|
+
# Delete a project skill
|
|
2096
|
+
skill_id = args.shift
|
|
2097
|
+
|
|
2098
|
+
unless skill_id
|
|
2099
|
+
display_message("Usage: aidp skill delete <skill-id>", type: :info)
|
|
2100
|
+
return
|
|
2101
|
+
end
|
|
2102
|
+
|
|
2103
|
+
begin
|
|
2104
|
+
registry = Aidp::Skills::Registry.new(project_dir: Dir.pwd)
|
|
2105
|
+
registry.load_skills
|
|
2106
|
+
|
|
2107
|
+
skill = registry.find(skill_id)
|
|
2108
|
+
|
|
2109
|
+
unless skill
|
|
2110
|
+
display_message("Skill not found: #{skill_id}", type: :error)
|
|
2111
|
+
return
|
|
2112
|
+
end
|
|
2113
|
+
|
|
2114
|
+
# Check if it's a project skill
|
|
2115
|
+
source = registry.by_source[skill_id]
|
|
2116
|
+
unless source == :project
|
|
2117
|
+
display_message("Cannot delete template skill '#{skill_id}'", type: :error)
|
|
2118
|
+
display_message("Only project skills in .aidp/skills/ can be deleted", type: :muted)
|
|
2119
|
+
return
|
|
2120
|
+
end
|
|
2121
|
+
|
|
2122
|
+
# Get skill directory
|
|
2123
|
+
skill_dir = File.dirname(skill.source_path)
|
|
2124
|
+
|
|
2125
|
+
# Confirm deletion
|
|
2126
|
+
require "tty-prompt"
|
|
2127
|
+
prompt = TTY::Prompt.new
|
|
2128
|
+
confirmed = prompt.yes?("Delete skill '#{skill.name}' (#{skill_id})? This cannot be undone.")
|
|
2129
|
+
|
|
2130
|
+
unless confirmed
|
|
2131
|
+
display_message("Deletion cancelled", type: :info)
|
|
2132
|
+
return
|
|
2133
|
+
end
|
|
2134
|
+
|
|
2135
|
+
# Delete the skill directory
|
|
2136
|
+
require "fileutils"
|
|
2137
|
+
FileUtils.rm_rf(skill_dir)
|
|
2138
|
+
|
|
2139
|
+
display_message("✓ Deleted skill: #{skill.name} (#{skill_id})", type: :success)
|
|
2140
|
+
rescue => e
|
|
2141
|
+
display_message("Failed to delete skill: #{e.message}", type: :error)
|
|
2142
|
+
Aidp.log_error("cli", "Skill deletion failed", error: e.message, backtrace: e.backtrace.first(5))
|
|
2143
|
+
end
|
|
2144
|
+
|
|
1896
2145
|
else
|
|
1897
2146
|
display_message("Usage: aidp skill <command>", type: :info)
|
|
1898
2147
|
display_message("", type: :info)
|
|
1899
2148
|
display_message("Commands:", type: :info)
|
|
1900
2149
|
display_message(" list List all available skills (default)", type: :info)
|
|
1901
2150
|
display_message(" show <id> Show detailed skill information", type: :info)
|
|
2151
|
+
display_message(" preview <id> Preview full SKILL.md content", type: :info)
|
|
2152
|
+
display_message(" diff <id> Show diff between project skill and template", type: :info)
|
|
1902
2153
|
display_message(" search <query> Search skills by keyword", type: :info)
|
|
2154
|
+
display_message(" new [options] Create a new skill using the wizard", type: :info)
|
|
2155
|
+
display_message(" edit <id> [options] Edit an existing skill", type: :info)
|
|
2156
|
+
display_message(" delete <id> Delete a project skill", type: :info)
|
|
1903
2157
|
display_message(" validate [path] Validate skill file format", type: :info)
|
|
1904
2158
|
display_message("", type: :info)
|
|
2159
|
+
display_message("New Skill Options:", type: :info)
|
|
2160
|
+
display_message(" --minimal Skip optional sections", type: :info)
|
|
2161
|
+
display_message(" --dry-run Preview without saving", type: :info)
|
|
2162
|
+
display_message(" --yes, -y Skip confirmation prompts", type: :info)
|
|
2163
|
+
display_message(" --id <skill_id> Pre-set skill ID", type: :info)
|
|
2164
|
+
display_message(" --name <name> Pre-set skill name", type: :info)
|
|
2165
|
+
display_message("", type: :info)
|
|
2166
|
+
display_message("Edit Skill Options:", type: :info)
|
|
2167
|
+
display_message(" --dry-run Preview changes without saving", type: :info)
|
|
2168
|
+
display_message(" --open-editor Open content in $EDITOR", type: :info)
|
|
2169
|
+
display_message("", type: :info)
|
|
1905
2170
|
display_message("Examples:", type: :info)
|
|
1906
2171
|
display_message(" aidp skill list # List all skills", type: :info)
|
|
1907
2172
|
display_message(" aidp skill show repository_analyst # Show skill details", type: :info)
|
|
2173
|
+
display_message(" aidp skill preview repository_analyst # Preview full content", type: :info)
|
|
2174
|
+
display_message(" aidp skill diff my_skill # Show diff with template", type: :info)
|
|
1908
2175
|
display_message(" aidp skill search git # Search for git-related skills", type: :info)
|
|
2176
|
+
display_message(" aidp skill new # Create new skill (interactive)", type: :info)
|
|
2177
|
+
display_message(" aidp skill new --minimal --id my_skill # Create with minimal prompts", type: :info)
|
|
2178
|
+
display_message(" aidp skill new --from-template repo_analyst # Inherit from template", type: :info)
|
|
2179
|
+
display_message(" aidp skill new --clone my_existing_skill # Clone existing skill", type: :info)
|
|
2180
|
+
display_message(" aidp skill edit repository_analyst # Edit existing skill", type: :info)
|
|
2181
|
+
display_message(" aidp skill delete my_custom_skill # Delete a project skill", type: :info)
|
|
1909
2182
|
display_message(" aidp skill validate skills/my_skill/SKILL.md # Validate specific skill", type: :info)
|
|
1910
2183
|
display_message(" aidp skill validate # Validate all skills", type: :info)
|
|
1911
2184
|
end
|
data/lib/aidp/config.rb
CHANGED
|
@@ -312,7 +312,7 @@ module Aidp
|
|
|
312
312
|
end
|
|
313
313
|
|
|
314
314
|
private_class_method def self.load_yaml_config(config_file)
|
|
315
|
-
YAML.
|
|
315
|
+
YAML.safe_load_file(config_file, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
316
316
|
rescue => e
|
|
317
317
|
warn "Failed to load configuration file #{config_file}: #{e.message}"
|
|
318
318
|
{}
|
|
@@ -26,6 +26,7 @@ module Aidp
|
|
|
26
26
|
@provider_manager = provider_manager
|
|
27
27
|
@config = config
|
|
28
28
|
@options = options
|
|
29
|
+
@cancel_timeout = options[:cancel_timeout] || 5 # seconds to wait for graceful shutdown
|
|
29
30
|
@state = WorkLoopState.new
|
|
30
31
|
@instruction_queue = InstructionQueue.new
|
|
31
32
|
@work_thread = nil
|
|
@@ -92,7 +93,7 @@ module Aidp
|
|
|
92
93
|
@state.append_output("Cancellation requested, waiting for safe stopping point...", type: :warning)
|
|
93
94
|
|
|
94
95
|
# Wait for thread to notice cancellation
|
|
95
|
-
@work_thread&.join(
|
|
96
|
+
@work_thread&.join(@cancel_timeout)
|
|
96
97
|
|
|
97
98
|
if save_checkpoint && @sync_runner
|
|
98
99
|
@state.append_output("Saving checkpoint before exit...", type: :info)
|
|
@@ -40,7 +40,7 @@ module Aidp
|
|
|
40
40
|
# Get the latest checkpoint data
|
|
41
41
|
def latest_checkpoint
|
|
42
42
|
return nil unless File.exist?(@checkpoint_file)
|
|
43
|
-
YAML.
|
|
43
|
+
YAML.safe_load_file(@checkpoint_file, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# Get checkpoint history for analysis
|
|
@@ -218,7 +218,7 @@ module Aidp
|
|
|
218
218
|
def load_existing_backlog
|
|
219
219
|
return unless File.exist?(@backlog_file)
|
|
220
220
|
|
|
221
|
-
data = YAML.
|
|
221
|
+
data = YAML.safe_load_file(@backlog_file, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
222
222
|
@entries = data["entries"] || [] if data.is_a?(Hash)
|
|
223
223
|
@entries = symbolize_keys_deep(@entries)
|
|
224
224
|
rescue => e
|
|
@@ -9,7 +9,7 @@ module Aidp
|
|
|
9
9
|
# - /split - Divide work into smaller contracts
|
|
10
10
|
# - /halt-on <pattern> - Pause on specific test failures
|
|
11
11
|
class ReplMacros
|
|
12
|
-
attr_reader :pinned_files, :focus_patterns, :halt_patterns, :split_mode, :current_workstream
|
|
12
|
+
attr_reader :pinned_files, :focus_patterns, :halt_patterns, :split_mode, :current_workstream, :current_skill
|
|
13
13
|
|
|
14
14
|
def initialize(project_dir: Dir.pwd)
|
|
15
15
|
@pinned_files = Set.new
|
|
@@ -18,6 +18,7 @@ module Aidp
|
|
|
18
18
|
@split_mode = false
|
|
19
19
|
@project_dir = project_dir
|
|
20
20
|
@current_workstream = nil
|
|
21
|
+
@current_skill = nil
|
|
21
22
|
@commands = register_commands
|
|
22
23
|
end
|
|
23
24
|
|
|
@@ -65,6 +66,7 @@ module Aidp
|
|
|
65
66
|
halt_patterns: @halt_patterns,
|
|
66
67
|
split_mode: @split_mode,
|
|
67
68
|
current_workstream: @current_workstream,
|
|
69
|
+
current_skill: @current_skill,
|
|
68
70
|
active_constraints: active_constraints_count
|
|
69
71
|
}
|
|
70
72
|
end
|
|
@@ -113,6 +115,30 @@ module Aidp
|
|
|
113
115
|
true
|
|
114
116
|
end
|
|
115
117
|
|
|
118
|
+
# Retrieve the current skill object, or nil if none is selected
|
|
119
|
+
#
|
|
120
|
+
# This method provides access to the full skill object (with content, providers, etc.)
|
|
121
|
+
# for the currently selected skill via `/skill use <id>`.
|
|
122
|
+
#
|
|
123
|
+
# @return [Aidp::Skills::Skill, nil] The current skill object or nil
|
|
124
|
+
#
|
|
125
|
+
# @example
|
|
126
|
+
# repl = ReplMacros.new(project_dir: Dir.pwd)
|
|
127
|
+
# repl.execute("/skill use repository_analyst")
|
|
128
|
+
# skill = repl.current_skill_object
|
|
129
|
+
# puts skill.content if skill # => skill's markdown content
|
|
130
|
+
def current_skill_object
|
|
131
|
+
return nil unless @current_skill
|
|
132
|
+
|
|
133
|
+
require_relative "../skills"
|
|
134
|
+
registry = Aidp::Skills::Registry.new(project_dir: @project_dir)
|
|
135
|
+
registry.load_skills
|
|
136
|
+
registry.find(@current_skill)
|
|
137
|
+
rescue => e
|
|
138
|
+
Aidp.log_error("repl_macros", "Failed to load current skill object", error: e.message)
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
116
142
|
private
|
|
117
143
|
|
|
118
144
|
# Register all available REPL commands
|
|
@@ -1257,25 +1283,25 @@ module Aidp
|
|
|
1257
1283
|
lines = ["Available Skills:", ""]
|
|
1258
1284
|
by_source = registry.by_source
|
|
1259
1285
|
|
|
1260
|
-
if by_source[:
|
|
1261
|
-
lines << "
|
|
1262
|
-
by_source[:
|
|
1286
|
+
if by_source[:template].any?
|
|
1287
|
+
lines << "Template Skills:"
|
|
1288
|
+
by_source[:template].each do |skill_id|
|
|
1263
1289
|
skill = registry.find(skill_id)
|
|
1264
1290
|
lines << " • #{skill_id} - #{skill.description}"
|
|
1265
1291
|
end
|
|
1266
1292
|
lines << ""
|
|
1267
1293
|
end
|
|
1268
1294
|
|
|
1269
|
-
if by_source[:
|
|
1270
|
-
lines << "
|
|
1271
|
-
by_source[:
|
|
1295
|
+
if by_source[:project].any?
|
|
1296
|
+
lines << "Project Skills:"
|
|
1297
|
+
by_source[:project].each do |skill_id|
|
|
1272
1298
|
skill = registry.find(skill_id)
|
|
1273
|
-
lines << " • #{skill_id} - #{skill.description} [
|
|
1299
|
+
lines << " • #{skill_id} - #{skill.description} [PROJECT]"
|
|
1274
1300
|
end
|
|
1275
1301
|
lines << ""
|
|
1276
1302
|
end
|
|
1277
1303
|
|
|
1278
|
-
lines << "Use '/skill show <id>' for details"
|
|
1304
|
+
lines << "Use '/skill show <id>' for details or '/skill use <id>' to activate"
|
|
1279
1305
|
|
|
1280
1306
|
{
|
|
1281
1307
|
success: true,
|
|
@@ -1412,10 +1438,53 @@ module Aidp
|
|
|
1412
1438
|
}
|
|
1413
1439
|
end
|
|
1414
1440
|
|
|
1441
|
+
when "use"
|
|
1442
|
+
# Switch to a specific skill
|
|
1443
|
+
skill_id = args.shift
|
|
1444
|
+
|
|
1445
|
+
unless skill_id
|
|
1446
|
+
return {
|
|
1447
|
+
success: false,
|
|
1448
|
+
message: "Usage: /skill use <skill-id>",
|
|
1449
|
+
action: :none
|
|
1450
|
+
}
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
begin
|
|
1454
|
+
registry = Aidp::Skills::Registry.new(project_dir: @project_dir)
|
|
1455
|
+
registry.load_skills
|
|
1456
|
+
|
|
1457
|
+
skill = registry.find(skill_id)
|
|
1458
|
+
|
|
1459
|
+
unless skill
|
|
1460
|
+
return {
|
|
1461
|
+
success: false,
|
|
1462
|
+
message: "Skill not found: #{skill_id}\nUse '/skill list' to see available skills",
|
|
1463
|
+
action: :none
|
|
1464
|
+
}
|
|
1465
|
+
end
|
|
1466
|
+
|
|
1467
|
+
# Store the current skill for the session
|
|
1468
|
+
@current_skill = skill_id
|
|
1469
|
+
|
|
1470
|
+
{
|
|
1471
|
+
success: true,
|
|
1472
|
+
message: "✓ Now using skill: #{skill.name} (#{skill_id})\n\n#{skill.description}",
|
|
1473
|
+
action: :switch_skill,
|
|
1474
|
+
data: {skill_id: skill_id, skill: skill}
|
|
1475
|
+
}
|
|
1476
|
+
rescue => e
|
|
1477
|
+
{
|
|
1478
|
+
success: false,
|
|
1479
|
+
message: "Failed to switch skill: #{e.message}",
|
|
1480
|
+
action: :none
|
|
1481
|
+
}
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1415
1484
|
else
|
|
1416
1485
|
{
|
|
1417
1486
|
success: false,
|
|
1418
|
-
message: "Usage: /skill <command> [args]\n\nCommands:\n list - List all available skills\n show <id> - Show detailed skill information\n search <query> - Search skills by keyword\n\nExamples:\n /skill list\n /skill show repository_analyst\n /skill search git",
|
|
1487
|
+
message: "Usage: /skill <command> [args]\n\nCommands:\n list - List all available skills\n show <id> - Show detailed skill information\n search <query> - Search skills by keyword\n use <id> - Switch to a specific skill\n\nExamples:\n /skill list\n /skill show repository_analyst\n /skill search git\n /skill use repository_analyst",
|
|
1419
1488
|
action: :none
|
|
1420
1489
|
}
|
|
1421
1490
|
end
|
|
@@ -256,7 +256,7 @@ module Aidp
|
|
|
256
256
|
return unless @config_file
|
|
257
257
|
|
|
258
258
|
begin
|
|
259
|
-
@config = YAML.
|
|
259
|
+
@config = YAML.safe_load_file(@config_file, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
260
260
|
rescue => e
|
|
261
261
|
@config = {}
|
|
262
262
|
@validation_result = {
|
|
@@ -213,7 +213,7 @@ module Aidp
|
|
|
213
213
|
return nil unless File.exist?(metadata_file)
|
|
214
214
|
|
|
215
215
|
# Return raw metadata with times as ISO8601 strings to avoid unsafe class loading
|
|
216
|
-
YAML.
|
|
216
|
+
YAML.safe_load_file(metadata_file, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
217
217
|
rescue
|
|
218
218
|
nil
|
|
219
219
|
end
|