aidp 0.14.1 → 0.15.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 +46 -45
- data/lib/aidp/cli.rb +46 -38
- data/lib/aidp/debug_mixin.rb +34 -33
- data/lib/aidp/execute/agent_signal_parser.rb +46 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +5 -0
- data/lib/aidp/execute/checkpoint.rb +28 -5
- data/lib/aidp/execute/deterministic_unit.rb +254 -0
- data/lib/aidp/execute/interactive_repl.rb +7 -0
- data/lib/aidp/execute/steps.rb +1 -1
- data/lib/aidp/execute/work_loop_runner.rb +187 -30
- data/lib/aidp/execute/work_loop_unit_scheduler.rb +190 -0
- data/lib/aidp/harness/config_schema.rb +91 -1
- data/lib/aidp/harness/configuration.rb +60 -1
- data/lib/aidp/harness/enhanced_runner.rb +2 -0
- data/lib/aidp/harness/provider_info.rb +14 -4
- data/lib/aidp/harness/provider_manager.rb +64 -12
- data/lib/aidp/jobs/background_runner.rb +10 -3
- data/lib/aidp/logger.rb +10 -71
- data/lib/aidp/providers/base.rb +2 -0
- data/lib/aidp/providers/github_copilot.rb +12 -0
- data/lib/aidp/rescue_logging.rb +36 -0
- data/lib/aidp/setup/wizard.rb +42 -46
- data/lib/aidp/storage/csv_storage.rb +33 -7
- data/lib/aidp/storage/json_storage.rb +33 -10
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/guided_agent.rb +95 -22
- data/templates/implementation/simple_task.md +5 -0
- metadata +5 -2
- data/lib/aidp/debug_logger.rb +0 -195
data/lib/aidp/logger.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Aidp
|
|
|
16
16
|
# Usage:
|
|
17
17
|
# Aidp.setup_logger(project_dir, config)
|
|
18
18
|
# Aidp.logger.info("component", "message", key: "value")
|
|
19
|
-
class
|
|
19
|
+
class Logger
|
|
20
20
|
LEVELS = {
|
|
21
21
|
debug: ::Logger::DEBUG,
|
|
22
22
|
info: ::Logger::INFO,
|
|
@@ -26,7 +26,6 @@ module Aidp
|
|
|
26
26
|
|
|
27
27
|
LOG_DIR = ".aidp/logs"
|
|
28
28
|
INFO_LOG = "#{LOG_DIR}/aidp.log"
|
|
29
|
-
DEBUG_LOG = "#{LOG_DIR}/aidp_debug.log"
|
|
30
29
|
|
|
31
30
|
DEFAULT_MAX_SIZE = 10 * 1024 * 1024 # 10MB
|
|
32
31
|
DEFAULT_MAX_FILES = 5
|
|
@@ -42,8 +41,7 @@ module Aidp
|
|
|
42
41
|
@max_files = config[:max_backups] || DEFAULT_MAX_FILES
|
|
43
42
|
|
|
44
43
|
ensure_log_directory
|
|
45
|
-
|
|
46
|
-
setup_loggers
|
|
44
|
+
setup_logger
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
# Log info level message
|
|
@@ -74,23 +72,12 @@ module Aidp
|
|
|
74
72
|
safe_message = redact(message)
|
|
75
73
|
safe_metadata = redact_hash(metadata)
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
if level == :debug
|
|
79
|
-
write_to_debug(level, component, safe_message, safe_metadata)
|
|
80
|
-
else
|
|
81
|
-
write_to_info(level, component, safe_message, safe_metadata)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Always log errors to both files
|
|
85
|
-
if level == :error
|
|
86
|
-
write_to_debug(level, component, safe_message, safe_metadata)
|
|
87
|
-
end
|
|
75
|
+
write_entry(level, component, safe_message, safe_metadata)
|
|
88
76
|
end
|
|
89
77
|
|
|
90
78
|
# Close all loggers
|
|
91
79
|
def close
|
|
92
|
-
@
|
|
93
|
-
@debug_logger&.close
|
|
80
|
+
@logger&.close
|
|
94
81
|
end
|
|
95
82
|
|
|
96
83
|
private
|
|
@@ -111,12 +98,9 @@ module Aidp
|
|
|
111
98
|
FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
|
|
112
99
|
end
|
|
113
100
|
|
|
114
|
-
def
|
|
101
|
+
def setup_logger
|
|
115
102
|
info_path = File.join(@project_dir, INFO_LOG)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
@info_logger = create_logger(info_path)
|
|
119
|
-
@debug_logger = create_logger(debug_path)
|
|
103
|
+
@logger = create_logger(info_path)
|
|
120
104
|
end
|
|
121
105
|
|
|
122
106
|
def create_logger(path)
|
|
@@ -126,14 +110,9 @@ module Aidp
|
|
|
126
110
|
logger
|
|
127
111
|
end
|
|
128
112
|
|
|
129
|
-
def
|
|
113
|
+
def write_entry(level, component, message, metadata)
|
|
130
114
|
entry = format_entry(level, component, message, metadata)
|
|
131
|
-
@
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def write_to_debug(level, component, message, metadata)
|
|
135
|
-
entry = format_entry(level, component, message, metadata)
|
|
136
|
-
@debug_logger.send(logger_method(level), entry)
|
|
115
|
+
@logger.send(logger_method(level), entry)
|
|
137
116
|
end
|
|
138
117
|
|
|
139
118
|
def logger_method(level)
|
|
@@ -205,58 +184,18 @@ module Aidp
|
|
|
205
184
|
def redact_hash(hash)
|
|
206
185
|
hash.transform_values { |v| v.is_a?(String) ? redact(v) : v }
|
|
207
186
|
end
|
|
208
|
-
|
|
209
|
-
# Migration from old debug_logs location
|
|
210
|
-
OLD_DEBUG_DIR = ".aidp/debug_logs"
|
|
211
|
-
OLD_DEBUG_LOG = "#{OLD_DEBUG_DIR}/aidp_debug.log"
|
|
212
|
-
|
|
213
|
-
def should_migrate?
|
|
214
|
-
old_path = File.join(@project_dir, OLD_DEBUG_LOG)
|
|
215
|
-
new_path = File.join(@project_dir, DEBUG_LOG)
|
|
216
|
-
|
|
217
|
-
# Migrate if old exists and new doesn't
|
|
218
|
-
File.exist?(old_path) && !File.exist?(new_path)
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def migrate_old_logs
|
|
222
|
-
old_path = File.join(@project_dir, OLD_DEBUG_LOG)
|
|
223
|
-
new_path = File.join(@project_dir, DEBUG_LOG)
|
|
224
|
-
|
|
225
|
-
begin
|
|
226
|
-
FileUtils.mv(old_path, new_path)
|
|
227
|
-
log_migration_notice
|
|
228
|
-
rescue => e
|
|
229
|
-
# If migration fails, just continue (new logs will be created)
|
|
230
|
-
warn "Failed to migrate old logs: #{e.message}"
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def log_migration_notice
|
|
235
|
-
notice = format_text(
|
|
236
|
-
:info,
|
|
237
|
-
"migration",
|
|
238
|
-
"Logs migrated from .aidp/debug_logs/ to .aidp/logs/",
|
|
239
|
-
timestamp: Time.now.utc.iso8601
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
# Write directly to avoid recursion
|
|
243
|
-
info_path = File.join(@project_dir, INFO_LOG)
|
|
244
|
-
File.open(info_path, "a") do |f|
|
|
245
|
-
f.puts notice
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
187
|
end
|
|
249
188
|
|
|
250
189
|
# Module-level logger accessor
|
|
251
190
|
class << self
|
|
252
191
|
# Set up global logger instance
|
|
253
192
|
def setup_logger(project_dir = Dir.pwd, config = {})
|
|
254
|
-
@logger =
|
|
193
|
+
@logger = Logger.new(project_dir, config)
|
|
255
194
|
end
|
|
256
195
|
|
|
257
196
|
# Get current logger instance (creates default if not set up)
|
|
258
197
|
def logger
|
|
259
|
-
@logger ||=
|
|
198
|
+
@logger ||= Logger.new
|
|
260
199
|
end
|
|
261
200
|
|
|
262
201
|
# Convenience logging methods
|
data/lib/aidp/providers/base.rb
CHANGED
|
@@ -86,6 +86,16 @@ module Aidp
|
|
|
86
86
|
# Log the results
|
|
87
87
|
debug_command("copilot", args: args, input: prompt, output: result.out, error: result.err, exit_code: result.exit_status)
|
|
88
88
|
|
|
89
|
+
# Detect authorization/access errors
|
|
90
|
+
auth_error = result.err.to_s =~ /not authorized|requires an enterprise|access denied|permission denied|not enabled/i
|
|
91
|
+
if auth_error
|
|
92
|
+
spinner.error("✗")
|
|
93
|
+
mark_failed("copilot authorization error: #{result.err}")
|
|
94
|
+
@unavailable = true
|
|
95
|
+
debug_error(StandardError.new("copilot authorization error"), {exit_code: result.exit_status, stderr: result.err})
|
|
96
|
+
raise Aidp::Providers::ProviderUnavailableError.new("copilot authorization error: #{result.err}")
|
|
97
|
+
end
|
|
98
|
+
|
|
89
99
|
if result.exit_status == 0
|
|
90
100
|
spinner.success("✓")
|
|
91
101
|
mark_completed
|
|
@@ -96,6 +106,8 @@ module Aidp
|
|
|
96
106
|
debug_error(StandardError.new("copilot failed"), {exit_code: result.exit_status, stderr: result.err})
|
|
97
107
|
raise "copilot failed with exit code #{result.exit_status}: #{result.err}"
|
|
98
108
|
end
|
|
109
|
+
rescue Aidp::Providers::ProviderUnavailableError
|
|
110
|
+
raise
|
|
99
111
|
rescue => e
|
|
100
112
|
spinner&.error("✗")
|
|
101
113
|
mark_failed("copilot execution failed: #{e.message}")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Aidp
|
|
5
|
+
# Mixin providing a unified helper for logging rescued exceptions.
|
|
6
|
+
# Usage:
|
|
7
|
+
# include Aidp::RescueLogging
|
|
8
|
+
# rescue => e
|
|
9
|
+
# log_rescue(e, component: "storage", action: "store file", fallback: {success: false})
|
|
10
|
+
#
|
|
11
|
+
# Defaults:
|
|
12
|
+
# - level: :warn (so filtering WARN surfaces rescue sites)
|
|
13
|
+
# - includes error class, message
|
|
14
|
+
# - optional fallback and extra context hash merged in
|
|
15
|
+
module RescueLogging
|
|
16
|
+
def log_rescue(error, component:, action:, fallback: nil, level: :warn, **context)
|
|
17
|
+
data = {
|
|
18
|
+
error_class: error.class.name,
|
|
19
|
+
error_message: error.message,
|
|
20
|
+
action: action
|
|
21
|
+
}
|
|
22
|
+
data[:fallback] = fallback if fallback
|
|
23
|
+
data.merge!(context) unless context.empty?
|
|
24
|
+
|
|
25
|
+
# Prefer debug_mixin if present; otherwise use Aidp.logger directly
|
|
26
|
+
if respond_to?(:debug_log)
|
|
27
|
+
debug_log("⚠️ Rescue in #{component}: #{action}", level: level, data: data)
|
|
28
|
+
else
|
|
29
|
+
Aidp.logger.send(level, component, "Rescued exception during #{action}", **data)
|
|
30
|
+
end
|
|
31
|
+
rescue => logging_error
|
|
32
|
+
# Last resort: avoid raising from logging path - fall back to STDERR
|
|
33
|
+
warn "[AIDP Rescue Logging Error] Failed to log rescue for #{component}:#{action} - #{error.class}: #{error.message} (logging error: #{logging_error.message})"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/aidp/setup/wizard.rb
CHANGED
|
@@ -143,46 +143,35 @@ module Aidp
|
|
|
143
143
|
# Save primary provider
|
|
144
144
|
set([:harness, :default_provider], provider_choice) unless provider_choice == "custom"
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
ensure_provider_billing_config(provider_choice) unless provider_choice == "custom"
|
|
147
|
+
|
|
148
|
+
# Prompt for fallback providers (excluding the primary), pre-select existing
|
|
149
|
+
existing_fallbacks = Array(get([:harness, :fallback_providers])).map(&:to_s) - [provider_choice]
|
|
147
150
|
fallback_choices = available_providers.reject { |_, name| name == provider_choice }
|
|
148
|
-
fallback_selected = prompt.multi_select("Select fallback providers (used if primary fails):") do |menu|
|
|
151
|
+
fallback_selected = prompt.multi_select("Select fallback providers (used if primary fails):", default: existing_fallbacks) do |menu|
|
|
149
152
|
fallback_choices.each do |display_name, provider_name|
|
|
150
153
|
menu.choice display_name, provider_name
|
|
151
154
|
end
|
|
152
155
|
end
|
|
153
156
|
|
|
154
|
-
#
|
|
157
|
+
# If user selected none but we had existing fallbacks, confirm removal
|
|
158
|
+
if fallback_selected.empty? && existing_fallbacks.any?
|
|
159
|
+
keep = prompt.no?("No fallbacks selected. Remove existing fallbacks (#{existing_fallbacks.join(", ")})?", default: false)
|
|
160
|
+
fallback_selected = existing_fallbacks if keep
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Remove any accidental duplication of primary provider & save (preserve order)
|
|
155
164
|
cleaned_fallbacks = fallback_selected.reject { |name| name == provider_choice }
|
|
156
165
|
set([:harness, :fallback_providers], cleaned_fallbacks)
|
|
157
166
|
|
|
158
|
-
#
|
|
167
|
+
# Auto-create minimal provider configs for fallbacks if missing
|
|
168
|
+
cleaned_fallbacks.each { |fp| ensure_provider_billing_config(fp) }
|
|
159
169
|
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
# Provide informational note (no secret handling stored)
|
|
171
|
+
show_provider_info_note(provider_choice) unless provider_choice == "custom"
|
|
162
172
|
end
|
|
163
173
|
|
|
164
|
-
|
|
165
|
-
existing = get([:providers, :mcp]) || {}
|
|
166
|
-
enabled = prompt.yes?("Enable MCP (Model Context Protocol) tools?", default: existing.fetch(:enabled, true))
|
|
167
|
-
return delete_path([:providers, :mcp]) unless enabled
|
|
168
|
-
|
|
169
|
-
# TODO: Add default back once TTY-Prompt default validation issue is resolved
|
|
170
|
-
tools = prompt.multi_select("Select MCP tools:") do |menu|
|
|
171
|
-
menu.choice "Git", "git"
|
|
172
|
-
menu.choice "Shell", "shell"
|
|
173
|
-
menu.choice "Filesystem", "fs"
|
|
174
|
-
menu.choice "Browser", "browser"
|
|
175
|
-
menu.choice "GitHub", "github"
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
custom = ask_list("Custom MCP servers (comma-separated)", existing.fetch(:custom_servers, []))
|
|
179
|
-
|
|
180
|
-
set([:providers, :mcp], {
|
|
181
|
-
enabled: true,
|
|
182
|
-
tools: tools,
|
|
183
|
-
custom_servers: custom
|
|
184
|
-
}.compact)
|
|
185
|
-
end
|
|
174
|
+
# Removed MCP configuration step (MCP now expected to be provider-specific if used)
|
|
186
175
|
|
|
187
176
|
# -------------------------------------------
|
|
188
177
|
# Work loop configuration
|
|
@@ -621,27 +610,34 @@ module Aidp
|
|
|
621
610
|
:other
|
|
622
611
|
end
|
|
623
612
|
|
|
624
|
-
def
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
613
|
+
def show_provider_info_note(provider)
|
|
614
|
+
prompt.say("\n💡 Provider integration:")
|
|
615
|
+
prompt.say("AIDP does not store API keys or model lists. Configure the agent (#{provider}) externally.")
|
|
616
|
+
prompt.say("Only the billing model (subscription vs usage_based) is recorded for fallback decisions.")
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
# Ensure a minimal billing configuration exists for a selected provider (no secrets)
|
|
620
|
+
def ensure_provider_billing_config(provider_name)
|
|
621
|
+
return if provider_name.nil? || provider_name == "custom"
|
|
622
|
+
providers_section = get([:providers]) || {}
|
|
623
|
+
existing = providers_section[provider_name.to_sym]
|
|
624
|
+
|
|
625
|
+
if existing && existing[:type]
|
|
626
|
+
prompt.say(" • Provider '#{provider_name}' already configured (type: #{existing[:type]})")
|
|
627
|
+
return
|
|
631
628
|
end
|
|
629
|
+
|
|
630
|
+
provider_type = ask_provider_billing_type(provider_name)
|
|
631
|
+
set([:providers, provider_name.to_sym], {type: provider_type})
|
|
632
|
+
prompt.say(" • Added provider '#{provider_name}' with billing type '#{provider_type}' (no secrets stored)")
|
|
632
633
|
end
|
|
633
634
|
|
|
634
|
-
def
|
|
635
|
-
prompt.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
prompt.say("Export API key: export OPENAI_API_KEY=sk-...")
|
|
641
|
-
when "google"
|
|
642
|
-
prompt.say("Export API key: export GOOGLE_API_KEY=...")
|
|
643
|
-
else
|
|
644
|
-
prompt.say("Configure API credentials via environment variables.")
|
|
635
|
+
def ask_provider_billing_type(provider_name)
|
|
636
|
+
prompt.select("Billing model for #{provider_name}:") do |menu|
|
|
637
|
+
menu.choice "Subscription / flat-rate", "subscription"
|
|
638
|
+
# e.g. tools that expose an integrated model under a subscription cost
|
|
639
|
+
menu.choice "Usage-based / metered (API)", "usage_based"
|
|
640
|
+
menu.choice "Passthrough / local (no billing)", "passthrough"
|
|
645
641
|
end
|
|
646
642
|
end
|
|
647
643
|
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require "csv"
|
|
4
4
|
require "fileutils"
|
|
5
|
+
require "aidp/rescue_logging"
|
|
5
6
|
|
|
6
7
|
module Aidp
|
|
7
8
|
module Storage
|
|
8
9
|
# Simple CSV file storage for tabular data
|
|
9
10
|
class CsvStorage
|
|
11
|
+
include Aidp::RescueLogging
|
|
12
|
+
|
|
10
13
|
def initialize(base_dir = ".aidp")
|
|
11
14
|
@base_dir = base_dir
|
|
12
15
|
ensure_directory_exists
|
|
@@ -42,11 +45,13 @@ module Aidp
|
|
|
42
45
|
success: true
|
|
43
46
|
}
|
|
44
47
|
rescue => error
|
|
45
|
-
|
|
48
|
+
log_rescue(error,
|
|
49
|
+
component: "csv_storage",
|
|
50
|
+
action: "append",
|
|
51
|
+
fallback: {success: false},
|
|
46
52
|
filename: filename,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
53
|
+
path: file_path)
|
|
54
|
+
{filename: filename, error: error.message, success: false}
|
|
50
55
|
end
|
|
51
56
|
|
|
52
57
|
# Read all rows from CSV file
|
|
@@ -60,7 +65,12 @@ module Aidp
|
|
|
60
65
|
end
|
|
61
66
|
rows
|
|
62
67
|
rescue => error
|
|
63
|
-
|
|
68
|
+
log_rescue(error,
|
|
69
|
+
component: "csv_storage",
|
|
70
|
+
action: "read_all",
|
|
71
|
+
fallback: [],
|
|
72
|
+
filename: filename,
|
|
73
|
+
path: (defined?(file_path) ? file_path : nil))
|
|
64
74
|
[]
|
|
65
75
|
end
|
|
66
76
|
|
|
@@ -83,7 +93,12 @@ module Aidp
|
|
|
83
93
|
CSV.foreach(file_path) { count += 1 }
|
|
84
94
|
count - 1 # Subtract 1 for header row
|
|
85
95
|
rescue => error
|
|
86
|
-
|
|
96
|
+
log_rescue(error,
|
|
97
|
+
component: "csv_storage",
|
|
98
|
+
action: "count_rows",
|
|
99
|
+
fallback: 0,
|
|
100
|
+
filename: filename,
|
|
101
|
+
path: (defined?(file_path) ? file_path : nil))
|
|
87
102
|
0
|
|
88
103
|
end
|
|
89
104
|
|
|
@@ -127,7 +142,12 @@ module Aidp
|
|
|
127
142
|
|
|
128
143
|
summary_data
|
|
129
144
|
rescue => error
|
|
130
|
-
|
|
145
|
+
log_rescue(error,
|
|
146
|
+
component: "csv_storage",
|
|
147
|
+
action: "summary",
|
|
148
|
+
fallback: nil,
|
|
149
|
+
filename: filename,
|
|
150
|
+
path: (defined?(file_path) ? file_path : nil))
|
|
131
151
|
nil
|
|
132
152
|
end
|
|
133
153
|
|
|
@@ -144,6 +164,12 @@ module Aidp
|
|
|
144
164
|
File.delete(file_path)
|
|
145
165
|
{success: true, message: "File deleted"}
|
|
146
166
|
rescue => error
|
|
167
|
+
log_rescue(error,
|
|
168
|
+
component: "csv_storage",
|
|
169
|
+
action: "delete",
|
|
170
|
+
fallback: {success: false},
|
|
171
|
+
filename: filename,
|
|
172
|
+
path: file_path)
|
|
147
173
|
{success: false, error: error.message}
|
|
148
174
|
end
|
|
149
175
|
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "fileutils"
|
|
5
|
+
require "aidp/rescue_logging"
|
|
5
6
|
|
|
6
7
|
module Aidp
|
|
7
8
|
module Storage
|
|
8
9
|
# Simple JSON file storage for structured data
|
|
9
10
|
class JsonStorage
|
|
11
|
+
include Aidp::RescueLogging
|
|
12
|
+
|
|
10
13
|
def initialize(base_dir = ".aidp")
|
|
11
14
|
@base_dir = base_dir
|
|
12
15
|
ensure_directory_exists
|
|
@@ -32,11 +35,13 @@ module Aidp
|
|
|
32
35
|
success: true
|
|
33
36
|
}
|
|
34
37
|
rescue => error
|
|
35
|
-
|
|
38
|
+
log_rescue(error,
|
|
39
|
+
component: "json_storage",
|
|
40
|
+
action: "store",
|
|
41
|
+
fallback: {success: false},
|
|
36
42
|
filename: filename,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
43
|
+
path: file_path)
|
|
44
|
+
{filename: filename, error: error.message, success: false}
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
# Load data from JSON file
|
|
@@ -48,7 +53,12 @@ module Aidp
|
|
|
48
53
|
json_data = JSON.parse(content)
|
|
49
54
|
json_data["data"]
|
|
50
55
|
rescue => error
|
|
51
|
-
|
|
56
|
+
log_rescue(error,
|
|
57
|
+
component: "json_storage",
|
|
58
|
+
action: "load",
|
|
59
|
+
fallback: nil,
|
|
60
|
+
filename: filename,
|
|
61
|
+
path: (defined?(file_path) ? file_path : nil))
|
|
52
62
|
nil
|
|
53
63
|
end
|
|
54
64
|
|
|
@@ -72,11 +82,13 @@ module Aidp
|
|
|
72
82
|
success: true
|
|
73
83
|
}
|
|
74
84
|
rescue => error
|
|
75
|
-
|
|
85
|
+
log_rescue(error,
|
|
86
|
+
component: "json_storage",
|
|
87
|
+
action: "update",
|
|
88
|
+
fallback: {success: false},
|
|
76
89
|
filename: filename,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
90
|
+
path: (defined?(file_path) ? file_path : nil))
|
|
91
|
+
{filename: filename, error: error.message, success: false}
|
|
80
92
|
end
|
|
81
93
|
|
|
82
94
|
# Check if file exists
|
|
@@ -92,6 +104,12 @@ module Aidp
|
|
|
92
104
|
File.delete(file_path)
|
|
93
105
|
{success: true, message: "File deleted"}
|
|
94
106
|
rescue => error
|
|
107
|
+
log_rescue(error,
|
|
108
|
+
component: "json_storage",
|
|
109
|
+
action: "delete",
|
|
110
|
+
fallback: {success: false},
|
|
111
|
+
filename: filename,
|
|
112
|
+
path: file_path)
|
|
95
113
|
{success: false, error: error.message}
|
|
96
114
|
end
|
|
97
115
|
|
|
@@ -120,7 +138,12 @@ module Aidp
|
|
|
120
138
|
size: File.size(file_path)
|
|
121
139
|
}
|
|
122
140
|
rescue => error
|
|
123
|
-
|
|
141
|
+
log_rescue(error,
|
|
142
|
+
component: "json_storage",
|
|
143
|
+
action: "metadata",
|
|
144
|
+
fallback: nil,
|
|
145
|
+
filename: filename,
|
|
146
|
+
path: (defined?(file_path) ? file_path : nil))
|
|
124
147
|
nil
|
|
125
148
|
end
|
|
126
149
|
|
data/lib/aidp/version.rb
CHANGED