aidp 0.24.0 → 0.25.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/README.md +27 -1
- data/lib/aidp/auto_update/bundler_adapter.rb +66 -0
- data/lib/aidp/auto_update/checkpoint.rb +178 -0
- data/lib/aidp/auto_update/checkpoint_store.rb +182 -0
- data/lib/aidp/auto_update/coordinator.rb +204 -0
- data/lib/aidp/auto_update/errors.rb +17 -0
- data/lib/aidp/auto_update/failure_tracker.rb +162 -0
- data/lib/aidp/auto_update/rubygems_api_adapter.rb +95 -0
- data/lib/aidp/auto_update/update_check.rb +106 -0
- data/lib/aidp/auto_update/update_logger.rb +143 -0
- data/lib/aidp/auto_update/update_policy.rb +109 -0
- data/lib/aidp/auto_update/version_detector.rb +144 -0
- data/lib/aidp/auto_update.rb +52 -0
- data/lib/aidp/cli.rb +165 -1
- data/lib/aidp/harness/config_schema.rb +50 -0
- data/lib/aidp/harness/provider_factory.rb +2 -0
- data/lib/aidp/message_display.rb +10 -2
- data/lib/aidp/prompt_optimization/style_guide_indexer.rb +3 -1
- data/lib/aidp/provider_manager.rb +2 -0
- data/lib/aidp/providers/kilocode.rb +202 -0
- data/lib/aidp/setup/provider_registry.rb +15 -0
- data/lib/aidp/setup/wizard.rb +12 -4
- data/lib/aidp/skills/composer.rb +4 -0
- data/lib/aidp/skills/loader.rb +3 -1
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +66 -16
- data/lib/aidp/watch/ci_fix_processor.rb +448 -0
- data/lib/aidp/watch/plan_processor.rb +12 -2
- data/lib/aidp/watch/repository_client.rb +380 -0
- data/lib/aidp/watch/review_processor.rb +266 -0
- data/lib/aidp/watch/reviewers/base_reviewer.rb +164 -0
- data/lib/aidp/watch/reviewers/performance_reviewer.rb +65 -0
- data/lib/aidp/watch/reviewers/security_reviewer.rb +65 -0
- data/lib/aidp/watch/reviewers/senior_dev_reviewer.rb +33 -0
- data/lib/aidp/watch/runner.rb +185 -0
- data/lib/aidp/watch/state_store.rb +53 -0
- data/lib/aidp.rb +1 -0
- metadata +20 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "update_check"
|
|
4
|
+
require_relative "update_policy"
|
|
5
|
+
require_relative "bundler_adapter"
|
|
6
|
+
require_relative "rubygems_api_adapter"
|
|
7
|
+
|
|
8
|
+
module Aidp
|
|
9
|
+
module AutoUpdate
|
|
10
|
+
# Service for detecting available gem versions and enforcing semver policy
|
|
11
|
+
class VersionDetector
|
|
12
|
+
def initialize(
|
|
13
|
+
policy:, current_version: Aidp::VERSION,
|
|
14
|
+
bundler_adapter: BundlerAdapter.new,
|
|
15
|
+
rubygems_adapter: RubyGemsAPIAdapter.new
|
|
16
|
+
)
|
|
17
|
+
@current_version = Gem::Version.new(current_version)
|
|
18
|
+
@policy = policy
|
|
19
|
+
@bundler_adapter = bundler_adapter
|
|
20
|
+
@rubygems_adapter = rubygems_adapter
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Check for updates according to policy
|
|
24
|
+
# @return [UpdateCheck] Result of update check
|
|
25
|
+
def check_for_update
|
|
26
|
+
Aidp.log_info("version_detector", "checking_for_updates",
|
|
27
|
+
current_version: @current_version.to_s,
|
|
28
|
+
policy: @policy.policy)
|
|
29
|
+
|
|
30
|
+
available_version = fetch_latest_version
|
|
31
|
+
|
|
32
|
+
unless available_version
|
|
33
|
+
Aidp.log_warn("version_detector", "no_version_available")
|
|
34
|
+
return UpdateCheck.unavailable(current_version: @current_version.to_s)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
update_available = available_version > @current_version
|
|
38
|
+
# Check policy even if disabled - we still want to report update_available
|
|
39
|
+
update_allowed = @policy.disabled? ? false : update_allowed_by_policy?(available_version)
|
|
40
|
+
reason = policy_reason(available_version)
|
|
41
|
+
|
|
42
|
+
Aidp.log_info("version_detector", "update_check_complete",
|
|
43
|
+
current: @current_version.to_s,
|
|
44
|
+
available: available_version.to_s,
|
|
45
|
+
update_available: update_available,
|
|
46
|
+
update_allowed: update_allowed,
|
|
47
|
+
reason: reason)
|
|
48
|
+
|
|
49
|
+
UpdateCheck.new(
|
|
50
|
+
current_version: @current_version.to_s,
|
|
51
|
+
available_version: available_version.to_s,
|
|
52
|
+
update_available: update_available,
|
|
53
|
+
update_allowed: update_allowed,
|
|
54
|
+
policy_reason: reason
|
|
55
|
+
)
|
|
56
|
+
rescue => e
|
|
57
|
+
Aidp.log_error("version_detector", "check_failed", error: e.message)
|
|
58
|
+
UpdateCheck.failed(e.message, current_version: @current_version.to_s)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Fetch latest version using bundler first, fallback to RubyGems API
|
|
64
|
+
# @return [Gem::Version, nil]
|
|
65
|
+
def fetch_latest_version
|
|
66
|
+
# Try bundler first
|
|
67
|
+
version = @bundler_adapter.latest_version_for("aidp")
|
|
68
|
+
return version if version
|
|
69
|
+
|
|
70
|
+
# Fallback to RubyGems API
|
|
71
|
+
Aidp.log_debug("version_detector", "falling_back_to_rubygems_api")
|
|
72
|
+
@rubygems_adapter.latest_version_for("aidp", allow_prerelease: @policy.allow_prerelease)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Apply semver policy to determine if update is allowed
|
|
76
|
+
# @param available [Gem::Version] Available version
|
|
77
|
+
# @return [Boolean] Whether update is permitted
|
|
78
|
+
def update_allowed_by_policy?(available)
|
|
79
|
+
case @policy.policy
|
|
80
|
+
when "off"
|
|
81
|
+
false
|
|
82
|
+
when "exact"
|
|
83
|
+
# Only update if exact match (essentially disabled)
|
|
84
|
+
available == @current_version
|
|
85
|
+
when "patch"
|
|
86
|
+
# Allow patch updates within same major.minor
|
|
87
|
+
same_major_minor?(available) && available >= @current_version
|
|
88
|
+
when "minor"
|
|
89
|
+
# Allow minor + patch updates within same major
|
|
90
|
+
same_major?(available) && available >= @current_version
|
|
91
|
+
when "major"
|
|
92
|
+
# Allow any update (including major version bumps)
|
|
93
|
+
available >= @current_version
|
|
94
|
+
else
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Generate human-readable reason for policy decision
|
|
100
|
+
# @param available [Gem::Version] Available version
|
|
101
|
+
# @return [String] Explanation of policy decision
|
|
102
|
+
def policy_reason(available)
|
|
103
|
+
return "No update available" if available <= @current_version
|
|
104
|
+
|
|
105
|
+
case @policy.policy
|
|
106
|
+
when "off"
|
|
107
|
+
"Updates disabled by policy"
|
|
108
|
+
when "exact"
|
|
109
|
+
"Policy requires exact version match"
|
|
110
|
+
when "patch"
|
|
111
|
+
if same_major_minor?(available)
|
|
112
|
+
"Patch update allowed by policy"
|
|
113
|
+
else
|
|
114
|
+
"Minor or major version change blocked by patch policy"
|
|
115
|
+
end
|
|
116
|
+
when "minor"
|
|
117
|
+
if same_major?(available)
|
|
118
|
+
"Minor/patch update allowed by policy"
|
|
119
|
+
else
|
|
120
|
+
"Major version change blocked by minor policy"
|
|
121
|
+
end
|
|
122
|
+
when "major"
|
|
123
|
+
"Update allowed by major policy"
|
|
124
|
+
else
|
|
125
|
+
"Unknown policy: #{@policy.policy}"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Check if version has same major version
|
|
130
|
+
# @param version [Gem::Version] Version to compare
|
|
131
|
+
# @return [Boolean]
|
|
132
|
+
def same_major?(version)
|
|
133
|
+
version.segments[0] == @current_version.segments[0]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Check if version has same major.minor version
|
|
137
|
+
# @param version [Gem::Version] Version to compare
|
|
138
|
+
# @return [Boolean]
|
|
139
|
+
def same_major_minor?(version)
|
|
140
|
+
same_major?(version) && version.segments[1] == @current_version.segments[1]
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "auto_update/errors"
|
|
4
|
+
require_relative "auto_update/update_policy"
|
|
5
|
+
require_relative "auto_update/update_check"
|
|
6
|
+
require_relative "auto_update/checkpoint"
|
|
7
|
+
require_relative "auto_update/bundler_adapter"
|
|
8
|
+
require_relative "auto_update/rubygems_api_adapter"
|
|
9
|
+
require_relative "auto_update/version_detector"
|
|
10
|
+
require_relative "auto_update/checkpoint_store"
|
|
11
|
+
require_relative "auto_update/update_logger"
|
|
12
|
+
require_relative "auto_update/failure_tracker"
|
|
13
|
+
require_relative "auto_update/coordinator"
|
|
14
|
+
|
|
15
|
+
module Aidp
|
|
16
|
+
# Auto-update functionality for Aidp in devcontainers
|
|
17
|
+
module AutoUpdate
|
|
18
|
+
# Exit code used to signal supervisor to perform update
|
|
19
|
+
UPDATE_EXIT_CODE = 75
|
|
20
|
+
|
|
21
|
+
# Create coordinator from project configuration
|
|
22
|
+
# @param project_dir [String] Project root directory
|
|
23
|
+
# @return [Coordinator]
|
|
24
|
+
def self.coordinator(project_dir: Dir.pwd)
|
|
25
|
+
config = Aidp::Config.load_harness_config(project_dir)
|
|
26
|
+
auto_update_config = config[:auto_update] || config["auto_update"] || {}
|
|
27
|
+
|
|
28
|
+
Coordinator.from_config(auto_update_config, project_dir: project_dir)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Check if auto-update is enabled in configuration
|
|
32
|
+
# @param project_dir [String] Project root directory
|
|
33
|
+
# @return [Boolean]
|
|
34
|
+
def self.enabled?(project_dir: Dir.pwd)
|
|
35
|
+
config = Aidp::Config.load_harness_config(project_dir)
|
|
36
|
+
auto_update_config = config[:auto_update] || config["auto_update"] || {}
|
|
37
|
+
|
|
38
|
+
policy = UpdatePolicy.from_config(auto_update_config)
|
|
39
|
+
!policy.disabled?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Get auto-update policy from configuration
|
|
43
|
+
# @param project_dir [String] Project root directory
|
|
44
|
+
# @return [UpdatePolicy]
|
|
45
|
+
def self.policy(project_dir: Dir.pwd)
|
|
46
|
+
config = Aidp::Config.load_harness_config(project_dir)
|
|
47
|
+
auto_update_config = config[:auto_update] || config["auto_update"] || {}
|
|
48
|
+
|
|
49
|
+
UpdatePolicy.from_config(auto_update_config)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/aidp/cli.rb
CHANGED
|
@@ -323,6 +323,11 @@ module Aidp
|
|
|
323
323
|
opts.separator " show <id> - Show detailed skill information"
|
|
324
324
|
opts.separator " search <query> - Search skills by keyword"
|
|
325
325
|
opts.separator " validate [path] - Validate skill file format"
|
|
326
|
+
opts.separator " settings Manage runtime settings"
|
|
327
|
+
opts.separator " auto-update status - Show auto-update configuration"
|
|
328
|
+
opts.separator " auto-update on|off - Enable/disable auto-updates"
|
|
329
|
+
opts.separator " auto-update policy <pol> - Set update policy (off/exact/patch/minor/major)"
|
|
330
|
+
opts.separator " auto-update prerelease - Toggle prerelease updates"
|
|
326
331
|
opts.separator " harness Manage harness state"
|
|
327
332
|
opts.separator " config Manage configuration"
|
|
328
333
|
opts.separator " status - Show harness status"
|
|
@@ -376,7 +381,7 @@ module Aidp
|
|
|
376
381
|
# Determine if the invocation is a subcommand style call
|
|
377
382
|
def subcommand?(args)
|
|
378
383
|
return false if args.nil? || args.empty?
|
|
379
|
-
%w[status jobs kb harness providers checkpoint mcp issue config init watch ws work skill].include?(args.first)
|
|
384
|
+
%w[status jobs kb harness providers checkpoint mcp issue config init watch ws work skill settings].include?(args.first)
|
|
380
385
|
end
|
|
381
386
|
|
|
382
387
|
def run_subcommand(args)
|
|
@@ -397,6 +402,7 @@ module Aidp
|
|
|
397
402
|
when "ws" then run_ws_command(args)
|
|
398
403
|
when "work" then run_work_command(args)
|
|
399
404
|
when "skill" then run_skill_command(args)
|
|
405
|
+
when "settings" then run_settings_command(args)
|
|
400
406
|
else
|
|
401
407
|
display_message("Unknown command: #{cmd}", type: :info)
|
|
402
408
|
return 1
|
|
@@ -1854,6 +1860,164 @@ module Aidp
|
|
|
1854
1860
|
display_message("Usage: aidp config --interactive [--dry-run]", type: :info)
|
|
1855
1861
|
end
|
|
1856
1862
|
|
|
1863
|
+
def run_settings_command(args)
|
|
1864
|
+
require_relative "auto_update"
|
|
1865
|
+
require "yaml"
|
|
1866
|
+
require "tty-table"
|
|
1867
|
+
|
|
1868
|
+
subcommand = args.shift
|
|
1869
|
+
|
|
1870
|
+
case subcommand
|
|
1871
|
+
when "auto-update"
|
|
1872
|
+
action = args.shift
|
|
1873
|
+
|
|
1874
|
+
case action
|
|
1875
|
+
when "status", nil
|
|
1876
|
+
# Show current auto-update status
|
|
1877
|
+
coordinator = Aidp::AutoUpdate.coordinator(project_dir: Dir.pwd)
|
|
1878
|
+
status = coordinator.status
|
|
1879
|
+
|
|
1880
|
+
display_message("Auto-Update Configuration", type: :highlight)
|
|
1881
|
+
display_message("=" * 60, type: :muted)
|
|
1882
|
+
display_message("Enabled: #{status[:enabled] ? "Yes" : "No"}", type: status[:enabled] ? :success : :muted)
|
|
1883
|
+
display_message("Policy: #{status[:policy]}", type: :info)
|
|
1884
|
+
display_message("Supervisor: #{status[:supervisor]}", type: :info)
|
|
1885
|
+
display_message("Allow Prerelease: #{coordinator.policy.allow_prerelease}", type: :info)
|
|
1886
|
+
display_message("Check Interval: #{coordinator.policy.check_interval_seconds}s", type: :info)
|
|
1887
|
+
display_message("Max Consecutive Failures: #{coordinator.policy.max_consecutive_failures}", type: :info)
|
|
1888
|
+
display_message("", type: :info)
|
|
1889
|
+
display_message("Current Version: #{status[:current_version]}", type: :info)
|
|
1890
|
+
display_message("Latest Available: #{status[:available_version] || "checking..."}", type: :info)
|
|
1891
|
+
|
|
1892
|
+
if status[:update_available]
|
|
1893
|
+
if status[:update_allowed]
|
|
1894
|
+
display_message("Update Available: Yes (allowed by policy)", type: :success)
|
|
1895
|
+
else
|
|
1896
|
+
display_message("Update Available: Yes (blocked by policy: #{status[:policy_reason]})", type: :warning)
|
|
1897
|
+
end
|
|
1898
|
+
else
|
|
1899
|
+
display_message("Update Available: No", type: :muted)
|
|
1900
|
+
end
|
|
1901
|
+
|
|
1902
|
+
display_message("", type: :info)
|
|
1903
|
+
display_message("Failure Tracker:", type: :highlight)
|
|
1904
|
+
failure_status = status[:failure_tracker]
|
|
1905
|
+
display_message("Consecutive Failures: #{failure_status[:failures]}/#{failure_status[:max_failures]}", type: :info)
|
|
1906
|
+
display_message("Last Success: #{failure_status[:last_success] || "never"}", type: :muted)
|
|
1907
|
+
|
|
1908
|
+
if status[:recent_updates]&.any?
|
|
1909
|
+
display_message("", type: :info)
|
|
1910
|
+
display_message("Recent Updates:", type: :highlight)
|
|
1911
|
+
status[:recent_updates].each do |entry|
|
|
1912
|
+
timestamp = entry["timestamp"] || entry[:timestamp]
|
|
1913
|
+
event = entry["event"] || entry[:event]
|
|
1914
|
+
display_message(" #{timestamp} - #{event}", type: :muted)
|
|
1915
|
+
end
|
|
1916
|
+
end
|
|
1917
|
+
|
|
1918
|
+
when "on"
|
|
1919
|
+
# Enable auto-update
|
|
1920
|
+
update_config_value(:auto_update, :enabled, true)
|
|
1921
|
+
display_message("✓ Auto-update enabled", type: :success)
|
|
1922
|
+
display_message("", type: :info)
|
|
1923
|
+
display_message("Make sure to configure a supervisor for watch mode.", type: :muted)
|
|
1924
|
+
display_message("See: docs/SELF_UPDATE.md", type: :muted)
|
|
1925
|
+
|
|
1926
|
+
when "off"
|
|
1927
|
+
# Disable auto-update
|
|
1928
|
+
update_config_value(:auto_update, :enabled, false)
|
|
1929
|
+
display_message("✓ Auto-update disabled", type: :success)
|
|
1930
|
+
|
|
1931
|
+
when "policy"
|
|
1932
|
+
# Set update policy
|
|
1933
|
+
policy = args.shift
|
|
1934
|
+
unless %w[off exact patch minor major].include?(policy)
|
|
1935
|
+
display_message("❌ Invalid policy. Must be: off, exact, patch, minor, major", type: :error)
|
|
1936
|
+
return
|
|
1937
|
+
end
|
|
1938
|
+
|
|
1939
|
+
update_config_value(:auto_update, :policy, policy)
|
|
1940
|
+
display_message("✓ Auto-update policy set to: #{policy}", type: :success)
|
|
1941
|
+
display_message("", type: :info)
|
|
1942
|
+
case policy
|
|
1943
|
+
when "off"
|
|
1944
|
+
display_message("No automatic updates will be performed", type: :muted)
|
|
1945
|
+
when "exact"
|
|
1946
|
+
display_message("Only exact version matches allowed", type: :muted)
|
|
1947
|
+
when "patch"
|
|
1948
|
+
display_message("Patch updates allowed (e.g., 1.2.3 → 1.2.4)", type: :muted)
|
|
1949
|
+
when "minor"
|
|
1950
|
+
display_message("Minor + patch updates allowed (e.g., 1.2.3 → 1.3.0)", type: :muted)
|
|
1951
|
+
when "major"
|
|
1952
|
+
display_message("All updates allowed (e.g., 1.2.3 → 2.0.0)", type: :muted)
|
|
1953
|
+
end
|
|
1954
|
+
|
|
1955
|
+
when "prerelease"
|
|
1956
|
+
# Toggle prerelease
|
|
1957
|
+
current = load_auto_update_config[:allow_prerelease]
|
|
1958
|
+
new_value = !current
|
|
1959
|
+
update_config_value(:auto_update, :allow_prerelease, new_value)
|
|
1960
|
+
display_message("✓ Prerelease updates: #{new_value ? "enabled" : "disabled"}", type: :success)
|
|
1961
|
+
|
|
1962
|
+
else
|
|
1963
|
+
display_message("Usage: aidp settings auto-update <command>", type: :info)
|
|
1964
|
+
display_message("", type: :info)
|
|
1965
|
+
display_message("Commands:", type: :info)
|
|
1966
|
+
display_message(" status Show current configuration", type: :info)
|
|
1967
|
+
display_message(" on Enable auto-updates", type: :info)
|
|
1968
|
+
display_message(" off Disable auto-updates", type: :info)
|
|
1969
|
+
display_message(" policy <policy> Set update policy", type: :info)
|
|
1970
|
+
display_message(" Policies: off, exact, patch, minor, major", type: :muted)
|
|
1971
|
+
display_message(" prerelease Toggle prerelease updates", type: :info)
|
|
1972
|
+
display_message("", type: :info)
|
|
1973
|
+
display_message("Examples:", type: :info)
|
|
1974
|
+
display_message(" aidp settings auto-update status", type: :info)
|
|
1975
|
+
display_message(" aidp settings auto-update on", type: :info)
|
|
1976
|
+
display_message(" aidp settings auto-update policy minor", type: :info)
|
|
1977
|
+
display_message(" aidp settings auto-update prerelease", type: :info)
|
|
1978
|
+
end
|
|
1979
|
+
|
|
1980
|
+
else
|
|
1981
|
+
display_message("Usage: aidp settings <category> <command>", type: :info)
|
|
1982
|
+
display_message("", type: :info)
|
|
1983
|
+
display_message("Categories:", type: :info)
|
|
1984
|
+
display_message(" auto-update Auto-update configuration", type: :info)
|
|
1985
|
+
display_message("", type: :info)
|
|
1986
|
+
display_message("Examples:", type: :info)
|
|
1987
|
+
display_message(" aidp settings auto-update status", type: :info)
|
|
1988
|
+
end
|
|
1989
|
+
end
|
|
1990
|
+
|
|
1991
|
+
# Load current auto_update config
|
|
1992
|
+
def load_auto_update_config
|
|
1993
|
+
config_path = File.join(Dir.pwd, ".aidp", "aidp.yml")
|
|
1994
|
+
return {} unless File.exist?(config_path)
|
|
1995
|
+
|
|
1996
|
+
full_config = YAML.safe_load_file(config_path, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
1997
|
+
full_config["auto_update"] || full_config[:auto_update] || {}
|
|
1998
|
+
end
|
|
1999
|
+
|
|
2000
|
+
# Update a specific configuration value
|
|
2001
|
+
def update_config_value(section, key, value)
|
|
2002
|
+
config_path = File.join(Dir.pwd, ".aidp", "aidp.yml")
|
|
2003
|
+
|
|
2004
|
+
# Load existing config
|
|
2005
|
+
config = if File.exist?(config_path)
|
|
2006
|
+
YAML.safe_load_file(config_path, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
2007
|
+
else
|
|
2008
|
+
{}
|
|
2009
|
+
end
|
|
2010
|
+
|
|
2011
|
+
# Ensure section exists
|
|
2012
|
+
config[section.to_s] ||= {}
|
|
2013
|
+
|
|
2014
|
+
# Update value
|
|
2015
|
+
config[section.to_s][key.to_s] = value
|
|
2016
|
+
|
|
2017
|
+
# Write back
|
|
2018
|
+
File.write(config_path, YAML.dump(config))
|
|
2019
|
+
end
|
|
2020
|
+
|
|
1857
2021
|
def run_skill_command(args)
|
|
1858
2022
|
require_relative "skills"
|
|
1859
2023
|
require "tty-table"
|
|
@@ -1083,6 +1083,56 @@ module Aidp
|
|
|
1083
1083
|
max: 365
|
|
1084
1084
|
}
|
|
1085
1085
|
}
|
|
1086
|
+
},
|
|
1087
|
+
auto_update: {
|
|
1088
|
+
type: :hash,
|
|
1089
|
+
required: false,
|
|
1090
|
+
default: {
|
|
1091
|
+
enabled: false,
|
|
1092
|
+
policy: "off",
|
|
1093
|
+
allow_prerelease: false,
|
|
1094
|
+
check_interval_seconds: 3600,
|
|
1095
|
+
supervisor: "none",
|
|
1096
|
+
max_consecutive_failures: 3
|
|
1097
|
+
},
|
|
1098
|
+
properties: {
|
|
1099
|
+
enabled: {
|
|
1100
|
+
type: :boolean,
|
|
1101
|
+
required: false,
|
|
1102
|
+
default: false
|
|
1103
|
+
},
|
|
1104
|
+
policy: {
|
|
1105
|
+
type: :string,
|
|
1106
|
+
required: false,
|
|
1107
|
+
default: "off",
|
|
1108
|
+
enum: ["off", "exact", "patch", "minor", "major"]
|
|
1109
|
+
},
|
|
1110
|
+
allow_prerelease: {
|
|
1111
|
+
type: :boolean,
|
|
1112
|
+
required: false,
|
|
1113
|
+
default: false
|
|
1114
|
+
},
|
|
1115
|
+
check_interval_seconds: {
|
|
1116
|
+
type: :integer,
|
|
1117
|
+
required: false,
|
|
1118
|
+
default: 3600,
|
|
1119
|
+
min: 300,
|
|
1120
|
+
max: 86400
|
|
1121
|
+
},
|
|
1122
|
+
supervisor: {
|
|
1123
|
+
type: :string,
|
|
1124
|
+
required: false,
|
|
1125
|
+
default: "none",
|
|
1126
|
+
enum: ["none", "supervisord", "s6", "runit"]
|
|
1127
|
+
},
|
|
1128
|
+
max_consecutive_failures: {
|
|
1129
|
+
type: :integer,
|
|
1130
|
+
required: false,
|
|
1131
|
+
default: 3,
|
|
1132
|
+
min: 1,
|
|
1133
|
+
max: 10
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1086
1136
|
}
|
|
1087
1137
|
}.freeze
|
|
1088
1138
|
|
|
@@ -6,6 +6,7 @@ require_relative "../providers/cursor"
|
|
|
6
6
|
require_relative "../providers/anthropic"
|
|
7
7
|
require_relative "../providers/gemini"
|
|
8
8
|
require_relative "../providers/opencode"
|
|
9
|
+
require_relative "../providers/kilocode"
|
|
9
10
|
require_relative "../providers/github_copilot"
|
|
10
11
|
require_relative "../providers/codex"
|
|
11
12
|
|
|
@@ -19,6 +20,7 @@ module Aidp
|
|
|
19
20
|
"claude" => Aidp::Providers::Anthropic,
|
|
20
21
|
"gemini" => Aidp::Providers::Gemini,
|
|
21
22
|
"opencode" => Aidp::Providers::Opencode,
|
|
23
|
+
"kilocode" => Aidp::Providers::Kilocode,
|
|
22
24
|
"github_copilot" => Aidp::Providers::GithubCopilot,
|
|
23
25
|
"codex" => Aidp::Providers::Codex
|
|
24
26
|
}.freeze
|
data/lib/aidp/message_display.rb
CHANGED
|
@@ -25,8 +25,12 @@ module Aidp
|
|
|
25
25
|
|
|
26
26
|
# Instance helper for displaying a colored message via TTY::Prompt
|
|
27
27
|
def display_message(message, type: :info)
|
|
28
|
+
# Ensure message is UTF-8 encoded to handle emoji and special characters
|
|
29
|
+
message_str = message.to_s
|
|
30
|
+
message_str = message_str.force_encoding("UTF-8") if message_str.encoding.name == "ASCII-8BIT"
|
|
31
|
+
message_str = message_str.encode("UTF-8", invalid: :replace, undef: :replace)
|
|
28
32
|
prompt = message_display_prompt
|
|
29
|
-
prompt.say(
|
|
33
|
+
prompt.say(message_str, color: COLOR_MAP.fetch(type, :white))
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
# Provide a memoized prompt per including instance (if it defines @prompt)
|
|
@@ -41,7 +45,11 @@ module Aidp
|
|
|
41
45
|
module ClassMethods
|
|
42
46
|
# Class-level display helper (uses fresh prompt to respect $stdout changes)
|
|
43
47
|
def display_message(message, type: :info)
|
|
44
|
-
|
|
48
|
+
# Ensure message is UTF-8 encoded to handle emoji and special characters
|
|
49
|
+
message_str = message.to_s
|
|
50
|
+
message_str = message_str.force_encoding("UTF-8") if message_str.encoding.name == "ASCII-8BIT"
|
|
51
|
+
message_str = message_str.encode("UTF-8", invalid: :replace, undef: :replace)
|
|
52
|
+
class_message_display_prompt.say(message_str, color: COLOR_MAP.fetch(type, :white))
|
|
45
53
|
end
|
|
46
54
|
|
|
47
55
|
private
|
|
@@ -82,7 +82,7 @@ module Aidp
|
|
|
82
82
|
guide_path = File.join(@project_dir, "docs", "LLM_STYLE_GUIDE.md")
|
|
83
83
|
return nil unless File.exist?(guide_path)
|
|
84
84
|
|
|
85
|
-
File.read(guide_path)
|
|
85
|
+
File.read(guide_path, encoding: "UTF-8")
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Parse markdown content into fragments
|
|
@@ -90,6 +90,8 @@ module Aidp
|
|
|
90
90
|
# @param content [String] Markdown content
|
|
91
91
|
# @return [Array<Fragment>] Parsed fragments
|
|
92
92
|
def parse_fragments(content)
|
|
93
|
+
# Ensure content is UTF-8 encoded
|
|
94
|
+
content = content.encode("UTF-8", invalid: :replace, undef: :replace) unless content.encoding == Encoding::UTF_8
|
|
93
95
|
lines = content.lines
|
|
94
96
|
current_content = []
|
|
95
97
|
current_heading = nil
|
|
@@ -142,6 +142,8 @@ module Aidp
|
|
|
142
142
|
Aidp::Providers::Anthropic.new(prompt: prompt)
|
|
143
143
|
when "gemini"
|
|
144
144
|
Aidp::Providers::Gemini.new(prompt: prompt)
|
|
145
|
+
when "kilocode"
|
|
146
|
+
Aidp::Providers::Kilocode.new(prompt: prompt)
|
|
145
147
|
when "github_copilot"
|
|
146
148
|
Aidp::Providers::GithubCopilot.new(prompt: prompt)
|
|
147
149
|
when "codex"
|